如何让正则表达式的第二个捕获组可选且不破坏匹配逻辑?
问题分析与正则修正
你的正则主要存在三个核心问题:
贪婪匹配导致最后一个数字无法捕获
匹配完<first>组后,.*是贪婪模式,会直接匹配到字符串末尾,使得<last>组没有剩余字符可匹配,最终只能为空。比如eightwothree,<first>捕获eight后,.*会吃掉wothree所有内容,<last>组无法捕获到three。单数字场景下
<last>组未正确赋值
当字符串只有一个数字时(如7pqrstsixteen),你的正则会让<last>组为空,但实际需要<last>和<first>捕获同一个数字。重叠数字拼写的匹配失效
对于twone这类重叠的数字拼写,你的正则匹配完two后,后续的one会被.*完全覆盖,无法被<last>组捕获。
修正后的正则
^(?=.*?(?<first>\d|one|two|three|four|five|six|seven|eight|nine|zero))(?s:.*)(?<last>\d|one|two|three|four|five|six|seven|eight|nine|zero)$
原理说明
- 正向预查捕获第一个数字:
(?=.*?(?<first>...))会在不消耗字符的前提下,找到字符串中第一个出现的数字并捕获到<first>组。 - 贪婪匹配到末尾:
(?s:.*)开启单行模式(让.匹配换行符),贪婪匹配所有内容到字符串末尾。 - 回溯捕获最后一个数字:
<last>组会从字符串末尾向前回溯,找到最后一个出现的数字并捕获,确保即使中间有重叠或多个数字,也能拿到最后一个。
测试用例验证
针对你给出的测试用例,修正后的正则会得到如下结果:
two1nine:<first>=two,<last>=nineeightwothree:<first>=eight,<last>=threeabcone2threexyz:<first>=one,<last>=threextwone3four:<first>=two,<last>=four4nineeightseven2:<first>=4,<last>=2zoneight234:<first>=one,<last>=47pqrstsixteen:<first>=7,<last>=78zckvmtmbjtdqprvfxtkmgmmtgck:<first>=8,<last>=8
内容的提问来源于stack exchange,提问作者online Thomas
相关产品推荐
相关产品推荐

