java解析sgf格式文件简单实现

围棋棋谱一般被保存为sgf格式,要想在自己的网站中实现打谱功能,必要要会解析sgf文件,取出里面的对局信息和落子,楼主现在用一种比较简单的方法来解析它

说明:楼主所用的棋谱是从新浪围棋里下载来的,示例用的是第10届中国围棋龙星战半决赛江维杰VS辜梓豪

文件内容如下(其他sgf格式也差不多,就是有些字段的名字换了一下)

(
TE[第10届中国围棋龙星战半决赛]
RD[2019-05-28]
PC[中国]
TM[0]
LT[30]
LC[10]
KO[7.5]
RE[黑中盘胜]
PB[江维杰]
BR[九段]
PW[辜梓豪]
WR[九段]
GK[1]
TC[]

;B[pd];W[dp];B[qp];W[dd];B[np];W[qc];B[qd];W[pc];B[nc];W[oc];B[od];W[nb];B[fq];W[hq]
;B[cc];W[cd];B[dc];W[ec];B[eb];W[fb];B[fc];W[ed];B[gb];W[db];B[fa];W[cb];B[fo];W[dm]
;B[jq];W[jp];B[kp];W[ip];B[ko];W[kq];B[kr];W[lq];B[ir];W[pp];B[po];W[qo];B[pq];W[hr]
;B[mq];W[in];B[bc];W[bb];B[er];W[dq];B[gn];W[il];B[gl];W[dk];B[cr];W[dr];B[ds];W[bq]
;B[el];W[dl];B[en];W[ij];B[fj];W[di];B[qn];W[fh];B[jk];W[ik];B[im];W[jm];B[hm];W[jo]
;B[jl];W[kn];B[lp];W[kl];B[kk];W[ll];B[lk];W[lo];B[lr];W[mk];B[ki];W[nl];B[hi];W[ni]
;B[mm];W[ml];B[jh];W[mc];B[nd];W[rc];B[pi];W[pk];B[ef];W[fd];B[lm];W[km];B[cg];W[ff]
;B[co];W[cn];B[cp];W[cq];B[do];W[bo];B[bk];W[bl];B[ci];W[gj];B[dh];W[gi];B[dj];W[ei]
;B[ej];W[ck];B[hh];W[gk];B[fg];W[eg];B[gg];W[eh];B[gh];W[fi];B[df];W[dg];B[ch];W[cf]
;B[bf];W[ce];B[fe];W[gf];B[ge];W[hf];B[ee];W[ig];B[hj];W[hk];B[ii];W[hc];B[gd];W[gc]
;B[hd];W[id];B[ic];W[fb];B[ie];W[jd];B[fc];W[hb];B[he];W[je];B[if];W[jf];B[hg];W[ng]
;B[qg];W[qj];B[md];W[lc];B[ob];W[mb];B[rd])

    需要的属性说明如下

      [TE]:比赛标题

      [RD]比赛时间 

      [PC]比赛地点

      [KO]贴目

      [RE]比赛结果

      [PB]黑方姓名

      [BR]黑方水平(职业)

      [PW]白方名字

      [WR]白方水平

     ;B[]黑方落子坐标

     ;W[]白棋落子坐标

实现

    1.先创建一个落子类,属性是落子的颜色、x坐标,与坐标以及步数

public class Point {
	private String color;
	private int x;
	private int y;
	private int step;
	
	public Point() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	public Point(String color, int x, int y,int step) {
		super();
		this.color = color;
		this.x = x;
		this.y = y;
		this.step = step;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

	public int getStep() {
		return step;
	}

	public void setStep(int step) {
		this.step = step;
	}
     		
}

  2.创建棋谱类,记录所有信息

//棋谱
public class ChessManual {
    private int manualid;
	private String title;// 比赛
	private String time;// 比赛时间
	private String dict;// 地点
	private float tiemu;// 贴目
	private String result;// 结果
	private String blackName;// 黑方
	private String blacklevel;// 黑方水平
	private String whiteName;// 白方
	private String whitelevel;// 白方水平
	private List<Point> playList;// 落子顺序
	
	public ChessManual() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	public ChessManual(String title, String time, String dict, float tiemu, String result, String blackName,
			String blacklevel, String whiteName, String whitelevel) {
		super();
		this.title = title;
		this.time = time;
		this.dict = dict;
		this.tiemu = tiemu;
		this.result = result;
		this.blackName = blackName;
		this.blacklevel = blacklevel;
		this.whiteName = whiteName;
		this.whitelevel = whitelevel;
	}

    

	public ChessManual(int manualid, String title, String time, String dict, float tiemu, String result,
			String blackName, String blacklevel, String whiteName, String whitelevel) {
		super();
		this.manualid = manualid;
		this.title = title;
		this.time = time;
		this.dict = dict;
		this.tiemu = tiemu;
		this.result = result;
		this.blackName = blackName;
		this.blacklevel = blacklevel;
		this.whiteName = whiteName;
		this.whitelevel = whitelevel;
	}

	public int getManualid() {
		return manualid;
	}

	public void setManualid(int manualid) {
		this.manualid = manualid;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getTime() {
		return time;
	}

	public void setTime(String time) {
		this.time = time;
	}

	public String getDict() {
		return dict;
	}

	public void setDict(String dict) {
		this.dict = dict;
	}

	public float getTiemu() {
		return tiemu;
	}

	public void setTiemu(float tiemu) {
		this.tiemu = tiemu;
	}

	public String getResult() {
		return result;
	}

	public void setResult(String result) {
		this.result = result;
	}

	public String getBlackName() {
		return blackName;
	}

	public void setBlackName(String blackName) {
		this.blackName = blackName;
	}

	public String getBlacklevel() {
		return blacklevel;
	}

	public void setBlacklevel(String blacklevel) {
		this.blacklevel = blacklevel;
	}

	public String getWhiteName() {
		return whiteName;
	}

	public void setWhiteName(String whiteName) {
		this.whiteName = whiteName;
	}

	public String getWhitelevel() {
		return whitelevel;
	}

	public void setWhitelevel(String whitelevel) {
		this.whitelevel = whitelevel;
	}

	public List<Point> getPlayList() {
		return playList;
	}

	public void setPlayList(List<Point> playList) {
		this.playList = playList;
	}

}

 3.解析类

     1.取内容函数:取到指定路径文件里的所有内容

//拿到文件内容
	public String getContent(String path) throws IOException {
		String result="";
		FileReader reader = new FileReader(path);
	    BufferedReader br = new BufferedReader(reader);
	    String line;
	    while ((line = br.readLine()) != null) {
	        result+=line;
	    }
	    return result;
	}

   如果是网络文件,就通过url拿到

//拿到文件内容
	public String getContent(String path) throws IOException {
		 URL url =new URL(path); // 创建URL
         URLConnection urlconn = url.openConnection(); // 试图连接并取得返回状态码
         urlconn.connect();
         HttpURLConnection httpconn =(HttpURLConnection)urlconn;
		 String result="";
		 InputStreamReader reader = new InputStreamReader(urlconn.getInputStream(),"GBK");
	
	     BufferedReader br = new BufferedReader(reader); // 建立一个对象,它把文件内容转成计算机能读懂的语言
	     String line;
	     //网友推荐更加简洁的写法
	     while ((line = br.readLine()) != null) {
	        result+=line;
	     }
	     return result;
	}

       

  

2.我们发现文件的有效信息都在 ’[‘ 和 ’]‘ 里,而且 '['前面都带有表明内容含义的字段,因此我们需要做的是取一个字符串中指定         开头字符和指定结尾字符中间的子字符串集合,因此我用了正则表达式来取

public static List<String> getStrContainData(String str, String start, String end){
		List<String> result = new ArrayList<>();
	    String regex = start + "(.*?)" + end;
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(str);
		while(matcher.find()){
			String key = matcher.group(1);
			if(!key.contains(start) && !key.contains(end)){
			    result.add(key);
			}
		}
		return result;
    }

     3.有了这个方法,那取信息就很方便了

      比如取标题是这样

ChessManual chessManual = new ChessManual();
//取比赛标题
List<String> result1 = getStrContainData(content, "TE\\[", "\\]");
for(String key : result1) {
   chessManual.setTitle(key);
}

      后面都差不多,最后讲讲取下棋步骤,列表中的每一项都是两个英文字母,而棋盘排列是从a开始的,因此只要求出两个字母在26个英文字母的位置即可得到坐标

楼主这里先取所有黑棋下的,在取白棋下棋,由于每个点都带有下棋步数,因此只需要这个list按下棋步数排列即可

//落子
        String s = "abcdefghijklmnopqrstuvwxyz";
		List<Point> moves = new ArrayList<Point>();
		//取出所有的黑棋落子
		List<String> result10 = getStrContainData(content,";B\\[","\\]");
		int i=0;
		for(String str : result10) {
			int x = s.indexOf(str.charAt(0));
			int y = s.indexOf(str.charAt(1));
			Point point = new Point("black",x,y,i*2+1);
			moves.add(point);
			i++;
		}
		
		//取出所有的白棋落子
		int j=0;
		List<String> result11 = getStrContainData(content,";W\\[","\\]");
		for(String str : result11) {
			int x = s.indexOf(str.charAt(0));
			int y = s.indexOf(str.charAt(1));
			Point point = new Point("white",x,y,j*2+2);
			moves.add(point);
			j++;
		}
		
		moves.sort(new Comparator<Point>() {

			@Override
			public int compare(Point o1, Point o2) {
				if(o1.getStep()>o2.getStep()) {
					return 1;
				}
				else {
					return -1;
				}
			}
			
		});

 下面是解析的全部代码

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.yizaiqianqiu.entity.ChessManual;
import com.yizaiqianqiu.entity.Point;

import net.sf.json.JSONObject;

public class ParseSGF {
	public ChessManual parseSGF(String path) throws IOException {
		ChessManual chessManual = new ChessManual();
		String content = getContent(path);
		String s = "abcdefghijklmnopqrstuvwxyz";
		//取比赛标题
		List<String> result1 = getStrContainData(content, "TE\\[", "\\]");
		for(String key : result1) {
			chessManual.setTitle(key);
		}
		//取比赛时间
		List<String> result2 = getStrContainData(content, "RD\\[", "\\]");
		for(String key : result2) {
			chessManual.setTime(key);
		}
		//取比赛地点
		List<String> result3 = getStrContainData(content, "PC\\[", "\\]");
		for(String key : result3) {
			chessManual.setDict(key);
		}
		
		//取出贴目
		List<String> result4 = getStrContainData(content, "KO\\[", "\\]");
		for(String key : result4) {
			chessManual.setTiemu(Float.parseFloat(key));
		}
		
		//取出结果
		List<String> result5 = getStrContainData(content, "RE\\[", "\\]");
		for(String key : result5) {
			chessManual.setResult(key);
		}
		
		//取出黑棋姓名
		List<String> result6 = getStrContainData(content,"PB\\[","\\]");
		for(String key : result6) {
			chessManual.setBlackName(key);
		}
		
		//取出黑棋水平
		List<String> result7 = getStrContainData(content,"BR\\[","\\]");
		for(String key : result7) {
			chessManual.setBlacklevel(key);
		}
		
		//取出白棋姓名
		List<String> result8 = getStrContainData(content,"PW\\[","\\]");
		for(String key : result8) {
			chessManual.setWhiteName(key);
		}
		
	    //取出白棋水平
		List<String> result9 = getStrContainData(content,"WR\\[","\\]");
		for(String key : result9) {
			chessManual.setWhitelevel(key);
		}
	     
		//落子
		List<Point> moves = new ArrayList<Point>();
		//取出所有的黑棋落子
		List<String> result10 = getStrContainData(content,";B\\[","\\]");
		int i=0;
		for(String str : result10) {
			int x = s.indexOf(str.charAt(0));
			int y = s.indexOf(str.charAt(1));
			Point point = new Point("black",x,y,i*2+1);
			moves.add(point);
			i++;
		}
		
		//取出所有的白棋落子
		int j=0;
		List<String> result11 = getStrContainData(content,";W\\[","\\]");
		for(String str : result11) {
			int x = s.indexOf(str.charAt(0));
			int y = s.indexOf(str.charAt(1));
			Point point = new Point("white",x,y,j*2+2);
			moves.add(point);
			j++;
		}
		
		moves.sort(new Comparator<Point>() {

			@Override
			public int compare(Point o1, Point o2) {
				if(o1.getStep()>o2.getStep()) {
					return 1;
				}
				else {
					return -1;
				}
			}
			
		});
		chessManual.setPlayList(moves);
		String str =JSONObject.fromObject(chessManual).toString();
		System.out.println(str);
		return chessManual;
	}
	//拿到文件内容
	public String getContent(String path) throws IOException {
		String result="";
		FileReader reader = new FileReader(path);
	    BufferedReader br = new BufferedReader(reader); // 建立一个对象,它把文件内容转成计算机能读懂的语言
	    String line;
	    //网友推荐更加简洁的写法
	    while ((line = br.readLine()) != null) {
	        result+=line;
	    }
	    return result;
	}
	
	public static List<String> getStrContainData(String str, String start, String end){
		List<String> result = new ArrayList<>();
	    String regex = start + "(.*?)" + end;
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(str);
		while(matcher.find()){
			String key = matcher.group(1);
			if(!key.contains(start) && !key.contains(end)){
			    result.add(key);
			}
		}
		return result;
    }
}

最后的结果我转成了json格式

{"blackName":"江维杰","blacklevel":"九段","dict":"中国","manualid":0,"playList":[{"color":"black","step":1,"x":15,"y":3},{"color":"white","step":2,"x":3,"y":15},{"color":"black","step":3,"x":16,"y":15},{"color":"white","step":4,"x":3,"y":3},{"color":"black","step":5,"x":13,"y":15},{"color":"white","step":6,"x":16,"y":2},{"color":"black","step":7,"x":16,"y":3},{"color":"white","step":8,"x":15,"y":2},{"color":"black","step":9,"x":13,"y":2},{"color":"white","step":10,"x":14,"y":2},{"color":"black","step":11,"x":14,"y":3},{"color":"white","step":12,"x":13,"y":1},{"color":"black","step":13,"x":5,"y":16},{"color":"white","step":14,"x":7,"y":16},{"color":"black","step":15,"x":2,"y":2},{"color":"white","step":16,"x":2,"y":3},{"color":"black","step":17,"x":3,"y":2},{"color":"white","step":18,"x":4,"y":2},{"color":"black","step":19,"x":4,"y":1},{"color":"white","step":20,"x":5,"y":1},{"color":"black","step":21,"x":5,"y":2},{"color":"white","step":22,"x":4,"y":3},{"color":"black","step":23,"x":6,"y":1},{"color":"white","step":24,"x":3,"y":1},{"color":"black","step":25,"x":5,"y":0},{"color":"white","step":26,"x":2,"y":1},{"color":"black","step":27,"x":5,"y":14},{"color":"white","step":28,"x":3,"y":12},{"color":"black","step":29,"x":9,"y":16},{"color":"white","step":30,"x":9,"y":15},{"color":"black","step":31,"x":10,"y":15},{"color":"white","step":32,"x":8,"y":15},{"color":"black","step":33,"x":10,"y":14},{"color":"white","step":34,"x":10,"y":16},{"color":"black","step":35,"x":10,"y":17},{"color":"white","step":36,"x":11,"y":16},{"color":"black","step":37,"x":8,"y":17},{"color":"white","step":38,"x":15,"y":15},{"color":"black","step":39,"x":15,"y":14},{"color":"white","step":40,"x":16,"y":14},{"color":"black","step":41,"x":15,"y":16},{"color":"white","step":42,"x":7,"y":17},{"color":"black","step":43,"x":12,"y":16},{"color":"white","step":44,"x":8,"y":13},{"color":"black","step":45,"x":1,"y":2},{"color":"white","step":46,"x":1,"y":1},{"color":"black","step":47,"x":4,"y":17},{"color":"white","step":48,"x":3,"y":16},{"color":"black","step":49,"x":6,"y":13},{"color":"white","step":50,"x":8,"y":11},{"color":"black","step":51,"x":6,"y":11},{"color":"white","step":52,"x":3,"y":10},{"color":"black","step":53,"x":2,"y":17},{"color":"white","step":54,"x":3,"y":17},{"color":"black","step":55,"x":3,"y":18},{"color":"white","step":56,"x":1,"y":16},{"color":"black","step":57,"x":4,"y":11},{"color":"white","step":58,"x":3,"y":11},{"color":"black","step":59,"x":4,"y":13},{"color":"white","step":60,"x":8,"y":9},{"color":"black","step":61,"x":5,"y":9},{"color":"white","step":62,"x":3,"y":8},{"color":"black","step":63,"x":16,"y":13},{"color":"white","step":64,"x":5,"y":7},{"color":"black","step":65,"x":9,"y":10},{"color":"white","step":66,"x":8,"y":10},{"color":"black","step":67,"x":8,"y":12},{"color":"white","step":68,"x":9,"y":12},{"color":"black","step":69,"x":7,"y":12},{"color":"white","step":70,"x":9,"y":14},{"color":"black","step":71,"x":9,"y":11},{"color":"white","step":72,"x":10,"y":13},{"color":"black","step":73,"x":11,"y":15},{"color":"white","step":74,"x":10,"y":11},{"color":"black","step":75,"x":10,"y":10},{"color":"white","step":76,"x":11,"y":11},{"color":"black","step":77,"x":11,"y":10},{"color":"white","step":78,"x":11,"y":14},{"color":"black","step":79,"x":11,"y":17},{"color":"white","step":80,"x":12,"y":10},{"color":"black","step":81,"x":10,"y":8},{"color":"white","step":82,"x":13,"y":11},{"color":"black","step":83,"x":7,"y":8},{"color":"white","step":84,"x":13,"y":8},{"color":"black","step":85,"x":12,"y":12},{"color":"white","step":86,"x":12,"y":11},{"color":"black","step":87,"x":9,"y":7},{"color":"white","step":88,"x":12,"y":2},{"color":"black","step":89,"x":13,"y":3},{"color":"white","step":90,"x":17,"y":2},{"color":"black","step":91,"x":15,"y":8},{"color":"white","step":92,"x":15,"y":10},{"color":"black","step":93,"x":4,"y":5},{"color":"white","step":94,"x":5,"y":3},{"color":"black","step":95,"x":11,"y":12},{"color":"white","step":96,"x":10,"y":12},{"color":"black","step":97,"x":2,"y":6},{"color":"white","step":98,"x":5,"y":5},{"color":"black","step":99,"x":2,"y":14},{"color":"white","step":100,"x":2,"y":13},{"color":"black","step":101,"x":2,"y":15},{"color":"white","step":102,"x":2,"y":16},{"color":"black","step":103,"x":3,"y":14},{"color":"white","step":104,"x":1,"y":14},{"color":"black","step":105,"x":1,"y":10},{"color":"white","step":106,"x":1,"y":11},{"color":"black","step":107,"x":2,"y":8},{"color":"white","step":108,"x":6,"y":9},{"color":"black","step":109,"x":3,"y":7},{"color":"white","step":110,"x":6,"y":8},{"color":"black","step":111,"x":3,"y":9},{"color":"white","step":112,"x":4,"y":8},{"color":"black","step":113,"x":4,"y":9},{"color":"white","step":114,"x":2,"y":10},{"color":"black","step":115,"x":7,"y":7},{"color":"white","step":116,"x":6,"y":10},{"color":"black","step":117,"x":5,"y":6},{"color":"white","step":118,"x":4,"y":6},{"color":"black","step":119,"x":6,"y":6},{"color":"white","step":120,"x":4,"y":7},{"color":"black","step":121,"x":6,"y":7},{"color":"white","step":122,"x":5,"y":8},{"color":"black","step":123,"x":3,"y":5},{"color":"white","step":124,"x":3,"y":6},{"color":"black","step":125,"x":2,"y":7},{"color":"white","step":126,"x":2,"y":5},{"color":"black","step":127,"x":1,"y":5},{"color":"white","step":128,"x":2,"y":4},{"color":"black","step":129,"x":5,"y":4},{"color":"white","step":130,"x":6,"y":5},{"color":"black","step":131,"x":6,"y":4},{"color":"white","step":132,"x":7,"y":5},{"color":"black","step":133,"x":4,"y":4},{"color":"white","step":134,"x":8,"y":6},{"color":"black","step":135,"x":7,"y":9},{"color":"white","step":136,"x":7,"y":10},{"color":"black","step":137,"x":8,"y":8},{"color":"white","step":138,"x":7,"y":2},{"color":"black","step":139,"x":6,"y":3},{"color":"white","step":140,"x":6,"y":2},{"color":"black","step":141,"x":7,"y":3},{"color":"white","step":142,"x":8,"y":3},{"color":"black","step":143,"x":8,"y":2},{"color":"white","step":144,"x":5,"y":1},{"color":"black","step":145,"x":8,"y":4},{"color":"white","step":146,"x":9,"y":3},{"color":"black","step":147,"x":5,"y":2},{"color":"white","step":148,"x":7,"y":1},{"color":"black","step":149,"x":7,"y":4},{"color":"white","step":150,"x":9,"y":4},{"color":"black","step":151,"x":8,"y":5},{"color":"white","step":152,"x":9,"y":5},{"color":"black","step":153,"x":7,"y":6},{"color":"white","step":154,"x":13,"y":6},{"color":"black","step":155,"x":16,"y":6},{"color":"white","step":156,"x":16,"y":9},{"color":"black","step":157,"x":12,"y":3},{"color":"white","step":158,"x":11,"y":2},{"color":"black","step":159,"x":14,"y":1},{"color":"white","step":160,"x":12,"y":1},{"color":"black","step":161,"x":17,"y":3}],"result":"黑中盘胜","tiemu":7.5,"time":"2019-05-28","title":"第10届中国围棋龙星战半决赛","whiteName":"辜梓豪","whitelevel":"九段"}

以上是楼主的简单实现,有更简单的方法,欢迎评论  

  

发布了8 篇原创文章 · 获赞 5 · 访问量 1410

猜你喜欢

转载自blog.csdn.net/qq_41957257/article/details/90750279