正则最小匹配失效时如何获取目标文本最近的前置数字
为什么非贪婪写法没有返回预期结果
正则的默认匹配规则是从字符串最左端开始逐位置扫描,只要在某个位置能凑出符合整个模式的完整匹配,就会直接返回结果,不会主动跳过更早的合法起点,去寻找离目标更近的匹配位置。
你写的(\d):evnt.*?MISS SCARLET里的.*?非贪婪,仅作用于当前匹配起点:当正则在字符串开头位置匹配到第一个0:evnt后,.*?会尽量少向后匹配字符,只要后续延伸能碰到MISS SCARLET,整个匹配就会成立。它不会主动跳过第一个出现的0:evnt,专门定位后面离目标更近的1:evnt,所以返回结果一直是0。
可用的正则方案
结合你给出的固定规则(两个数字+:evnt结构之间不会出现其他evnt标记、单个evnt段不会包含多个姓名),以下两种写法都能稳定拿到正确结果:
简洁通用写法(兼容所有常见正则引擎)
把模式末尾的姓名替换成你要查找的目标即可:
.*(\d+):evnt.*?MISS SCARLET
匹配逻辑
- 开头的
.*是贪婪匹配,会优先匹配尽可能长的内容,直接走到字符串末尾 - 之后正则引擎开始回溯,从后往前找第一个符合
数字+:evnt结构的位置,这个位置必然是离目标姓名最近的前置evnt标记 - 找到对应evnt后,用非贪婪的
.*?匹配evnt到目标姓名之间的随机内容,第一个捕获组的内容就是你要的数字
测试结果
针对你提供的示例字符串:
- 查找目标为
MISTER GREEN时,捕获组返回0 - 查找目标为
MISS SCARLET时,捕获组返回1
低回溯高性能写法
如果待匹配的文本量很大,可以用负向预查减少回溯开销,不需要从字符串末尾往回找:
(\d+):evnt(?:(?!:evnt).)*?MISS SCARLET
这个写法的逻辑是:每匹配到一个数字+:evnt结构,就向后检查后续内容,只要中间不出现新的:evnt标记,一直匹配到目标姓名就算成功,天然就能定位到离目标最近的evnt,不会匹配到更早的编号。
提示:如果你的场景里编号可能是多位数字,一定要用
\d+而不是单个\d,避免匹配失败。
内容的提问来源于stack exchange,提问作者bcsteeve
相关产品推荐
相关产品推荐

