保龄球得分匹配Regex问题:后行断言与重复捕获组应用
嘿,我来帮你搞定保龄球得分的正则匹配问题!你遇到的重复捕获组只抓最后一次的问题,其实是正则引擎的固有特性,咱们换个思路就能解决,还能拆成JSON子模式方便维护,一步步来:
保龄球得分匹配与计算的正则方案(JSON结构)
核心问题拆解
首先得明确:你之前碰到的重复捕获组只保留最后一次结果是正则的常规操作——当你用(...)重复匹配时,引擎只会存储最后一次匹配的内容。所以要获取所有10帧的得分,不能靠单个重复捕获组,得把每帧的模式明确拆分,同时单独处理第10帧的特殊规则(因为第10帧允许额外击球,直接关联奖励球的数量)。
第一步:拆分正则子模式(JSON结构)
我们可以把不同的符号规则拆成独立的子模式,方便维护和组合,JSON结构如下:
{ "subPatterns": { "miss": "-", "digit": "[0-9]", "strike": "X", "spare": "(?<!X)(\\d|-)/", // 补中不能以全中开头,用后行断言排除前面是X的情况 "singleBall": "(?:X|\\d|-)", // 单个有效击球:全中、数字、失误 "frameNormal": "(?:X|(?:\\d|-)(?:\\d|-|/))", // 前9帧的有效格式:要么全中,要么两个球(含补中) "frame10": "(?:X(?:X|\\d|-){0,2}|(?:\\d|-)/\\d|(?:\\d|-){2})", // 第10帧的所有合法情况 "rewardArea": "(?:\\|(?:X|\\d|-){0,2})?" // 奖励区:根据第10帧情况匹配0-2个球 }, "fullPattern": "^(?:(?<frame>[X\\d-](?:[\\d-/]|(?<=X))\\|){9}(?<frame10>X(?:X\\d|-){0,2}|[\\d-]/[\\d-]|[\\d-]{2})\\|(?<reward>[X\\d-]{0,2})\\|)?$" }
子模式细节说明
miss:匹配失误符号-digit:匹配0-9的数字得分strike:匹配全中Xspare:用后行断言(?<!X)确保补中前面不是全中(符合规则:补中只能是同一帧的第二个球)singleBall:单个有效击球的统一模式,方便复用frameNormal:前9帧的通用格式,要么一个全中,要么两个球(包含补中)frame10:覆盖第10帧的三种合法场景:- 全中后接0-2个额外球(对应奖励球规则)
- 补中后接1个额外球
- 普通的两个非全中/非补中的球
rewardArea:自动匹配奖励区,根据第10帧的结果对应0-2个球
第二步:解决分组捕获问题
要获取所有10帧的得分,我们可以给前9帧分别设置命名捕获组(避免重复组的坑),全量匹配正则如下:
^(?<frame1>X|[\d-][\d-/])\| (?<frame2>X|[\d-][\d-/])\| (?<frame3>X|[\d-][\d-/])\| (?<frame4>X|[\d-][\d-/])\| (?<frame5>X|[\d-][\d-/])\| (?<frame6>X|[\d-][\d-/])\| (?<frame7>X|[\d-][\d-/])\| (?<frame8>X|[\d-][\d-/])\| (?<frame9>X|[\d-][\d-/])\| (?<frame10>X(?:X|[\d-]){0,2}|[\d-]/[\d-]|[\d-]{2})\| (?<reward>[X\d-]{0,2})\|$
这个正则把前9帧分别用frame1到frame9命名捕获,第10帧用frame10,奖励区用reward,这样就能拿到每帧的具体内容,完美避开重复捕获组只存最后一次的问题。
第三步:通过匹配组推导总分的逻辑
拿到每个捕获组的内容后,按规则计算总分:
- 前9帧得分:
- 全中
X:得10分 + 下两球的得分(比如当前帧是X,取后面一帧的前两球,或第10帧的球) - 补中
x/(比如5/):得10分 + 下一球的得分 - 普通球(比如
3-或45):直接相加数字(-算0分)
- 全中
- 第10帧得分:
- 全中:10分 + 两个奖励球的得分(如果有)
- 补中:10分 + 一个奖励球的得分(如果有)
- 普通球:直接相加数字
- 注意:奖励球仅用于计算前9帧的全中/补中加分,本身不单独计入总分
举个例子:完美比赛得分串X|X|X|X|X|X|X|X|X|XXX||
- 前9帧每个全中都是10 + 后面两球的10+10,9*30=270
- 第10帧三个全中得30分,总分300
补充:关于后行断言的使用
你之前用(?<!X)排除补中前面是全中的思路是对的,完全符合保龄球规则(补中不能接在全中后面)。在第10帧的模式里,我们已经把这种非法情况排除在外,所以整个正则只会匹配合法的得分格式。
内容的提问来源于stack exchange,提问作者Dodomac
相关产品推荐
相关产品推荐

