基于Peggy实现完整SGF语法解析的递归逻辑问题求助
用Peggy实现SGF递归结构解析的解决方案
核心问题拆解
SGF的递归核心在于GameTree的嵌套(一个GameTree可包含多个子GameTree),以及Value中允许转义括号的字符串规则。你的解析结果为字符数组,本质是规则未返回结构化对象,而是直接返回匹配的字符流。
分步实现规则
下面是完整的Peggy语法规则,每个规则都返回你需要的JSON树形结构:
1. 基础字符与辅助规则
先定义最底层的字符匹配,处理转义逻辑:
// 跳过任意空白符(SGF允许语法元素间加空格、换行等) _ = [ \t\n\r]* // 转义字符:匹配\(、\)、\\三种转义情况 EscapedChar = "\\" ( "(" / ")" / "\\" ) // 非括号、非转义的普通字符 NormalChar = [^()\\] // 合法的Value字符:普通字符或转义字符 ValueChar = NormalChar / EscapedChar
2. 核心结构化规则
Value规则(处理带转义括号的字符串)
Value = value:$(ValueChar+) { // 还原转义字符:把\(转为(,\)转为),\\转为\ return value.replace(/\\(.)/g, "$1"); }
Property规则(属性键值对,如B[aa]、W[bb])
// 属性ID:大写字母开头,可后跟多个大写字母/数字 PropertyID = id:$([A-Z][A-Z0-9]*) { return id; } // 单个属性:ID后跟1个或多个Value(用[]包裹) Property = _ id:PropertyID _ "[" _ values:(Value (_ Value)*)? _ "]" _ { return { [id]: values ? values.filter(v => v) : [] }; }
Node规则(节点,以;开头,包含多个属性)
Node = _ ";" _ props:(Property*) _ { // 合并所有属性到一个data对象 const data = props.reduce((acc, prop) => ({ ...acc, ...prop }), {}); return { data, children: [] }; // 初始子节点为空,后续由GameTree填充 }
Sequence规则(连续节点序列)
Sequence = nodes:(Node+) { return nodes; }
GameTree规则(递归核心:括号包裹序列+子GameTree)
GameTree = _ "(" _ seq:Sequence _ children:(GameTree*) _ ")" _ { // 生成你需要的Branch结构:包含节点序列和子分支 return { moves: seq, children: children }; }
Collection规则(顶级结构:多个GameTree)
Collection = trees:(GameTree+) _ { return trees; }
3. 启动解析
将Collection设为起始规则,解析后会返回顶级GameTree数组,每个GameTree包含moves(节点序列)和children(子分支),每个节点有data(属性键值对)和children(子分支挂载入口)。
关键注意事项
- 递归终止逻辑:Peggy会自动识别闭合括号作为递归终止条件,无需手动控制层级,只要规则定义正确即可。
- 空白符兼容:所有规则间加入
_跳过空白,完全符合SGF允许任意空白的语法规范。 - 结构化返回:每个规则必须返回对象/数组,而非默认的字符匹配结果,这是从字符数组转为树形结构的核心。
示例解析效果
输入SGF片段:
(;B[aa];W[bb](;B[ac];W[bc])(;B[ca];W[cb]))
解析后生成的JSON结构:
[ { "moves": [ { "data": { "B": ["aa"] }, "children": [] }, { "data": { "W": ["bb"] }, "children": [] } ], "children": [ { "moves": [ { "data": { "B": ["ac"] }, "children": [] }, { "data": { "W": ["bc"] }, "children": [] } ], "children": [] }, { "moves": [ { "data": { "B": ["ca"] }, "children": [] }, { "data": { "W": ["cb"] }, "children": [] } ], "children": [] } ] } ]
内容的提问来源于stack exchange,提问作者psygo
相关产品推荐
相关产品推荐

