如何用Regex搜索国际棋谱中白方连续5次骑士移动的多变量模式?
国际象棋棋谱搜索:白方连续5次骑士移动的正则与实现方案
需求明确
要在数千行棋谱文本中定位包含**白方连续5次骑士移动(N,大小写敏感)**的对局,棋谱格式规则:
##.:无前导零的走步编号(如2.、15.)N***:白方骑士走子,***为位置(可选含x表示吃子,后跟a-h列+1-8行,如Nc3、Nxh8)X***:黑方走子,X可为N/R/B/K/Q(对应棋子)或无(兵走子),***规则同白方- 各组分以空格分隔
正则表达式设计
核心子模式拆解
白方骑士走步:匹配完整的白方骑士回合前缀+走子
\b[1-9]\d*\.\sNx?[a-h][1-8]\b\b:单词边界,避免编号与其他数字混淆[1-9]\d*\.\s:无前导零的编号+句号+空格Nx?[a-h][1-8]:严格匹配白方骑士走子(可选x吃子,位置合法)
黑方任意走步:覆盖黑方所有合法走子类型
\b(?:[NRBKQ]x?[a-h][1-8]|[a-h][1-8]x?[a-h][1-8]|[a-h][1-8])\b(?:...):非捕获组,仅用于分组不保留匹配结果- 三种分支分别对应:黑方棋子走子、兵吃子、普通兵走子
完整匹配正则(连续5次白方骑士)
5次白方走子之间包含4次黑方走子,因此组合为:
\b(?:[1-9]\d*\.\sNx?[a-h][1-8]\s+(?:[NRBKQ]x?[a-h][1-8]|[a-h][1-8]x?[a-h][1-8]|[a-h][1-8])\s+){4}[1-9]\d*\.\sNx?[a-h][1-8]\b
{4}:重复4次「白方骑士走步+黑方走步」的组合- 最后追加1次白方骑士走步,完成连续5次的匹配
JavaScript实现方案
全局遍历所有匹配(含位置)
使用matchAll方法获取所有匹配结果及起始位置,替代仅返回首个匹配的方法:
// 假设chessText为加载后的完整棋谱文本 const chessText = `[Event "Live Chess"] [Site "Chess.com"] [Date "2023.02.17"] [Round "-"] [White "-"] [Black "-"] [Result "1-0"] [WhiteElo "925"] [BlackElo "939"] [TimeControl "180+2"] [EndTime "17:39:13 PST"] [Termination "- won by checkmate"] e4 e5 2. Nc3 d6 3. Bc4 h6 4. d3 Nc6 5. f4 Qe7 6. Nf3 Be6 7. f5 Bxc4 8. dxc4 O-O-O 9. b3 Nf6 10. O-O g5 11. fxg6 fxg6 12. Nh4 g5 13. Ng6 Qg7 14. Nxh8 Qxh8 15. Nd5 Nxd5 16. exd5 Nd4 17. c3 Nxb3 18. axb3 a6 19. b4 Be7 20. Qg4+ Kb8 21. b5 axb5 22. cxb5 b6 23. Qa4 Kc8 24. Qa8+ Kd7 25. Qc6+ Kc8 26. Ra8# 1-0 [Event "Live Chess"] [Site "Chess.com"] [Date "2023.02.17"] [Round "-"] [White "-"] [Black "-"] [Result "1-0"] [WhiteElo "914"] [BlackElo "841"] [TimeControl "180+2"] [EndTime "19:06:57 PST"] [Termination "- won by resignation"] e4 e5 2. Nc3 Nc6 3. Bc4 Nf6 4. d3 Bc5 5. Na4 Bb4+ 6. c3 Be7 7. f4 b5 8. Bxb5 a6 9. Bc4 O-O 10. f5 d5 11. exd5 Nxd5 12. Nf3 Bxf5 13. O-O Bc5+ 14. Nxc5 Nf4 15. Nxe5 Nxe5 16. Rxf4 Bg4 17. Rxg4 Nxg4 18. Qxg4 Re8 19. Bh6 g6 1-0`; const regex = /\b(?:[1-9]\d*\.\sNx?[a-h][1-8]\s+(?:[NRBKQ]x?[a-h][1-8]|[a-h][1-8]x?[a-h][1-8]|[a-h][1-8])\s+){4}[1-9]\d*\.\sNx?[a-h][1-8]\b/g; // 遍历所有匹配结果 for (const match of chessText.matchAll(regex)) { console.log(`匹配内容: ${match[0]}`); console.log(`起始位置: ${match.index}`); }
效率优化:按对局分割搜索
棋谱以[Event ...]作为对局起始标记,先将文本分割为单个对局,再逐个检查,避免全局扫描大文件:
// 分割为单个对局数组 const games = chessText.split(/^\[Event/m).filter(game => game.trim()); // 遍历每个对局查找匹配 games.forEach((game, index) => { if (regex.test(game)) { console.log(`找到目标对局,索引: ${index}`); console.log(`对局内容开头: ${game.slice(0, 100)}...`); } });
测试说明
你提供的两个测试对局中:
- 第一局包含4次连续白方骑士移动(
Nh4、Ng6、Nxh8、Nd5),未达到5次,不会匹配正则; - 第二局的白方骑士走子被其他白方走步打断,并非连续5次,也不会匹配。
内容的提问来源于stack exchange,提问作者Charles Crawford
相关产品推荐
相关产品推荐

