如何让ECMAScript正则的\w+既不抢占_(\d+)又保留单捕获组?
正则表达式匹配问题解决方案
问题说明
你有一堆用英文句点(.)分隔的重复格式文本,部分文本会以_123这种“下划线+数字串”的形式结尾,需要把末尾的数字单独捕获到一个分组里。你写的正则/(label(:|\+))?(\w+)(?:_(\d+))?/gi多数情况能用,但有两个坑:
- 因为
\w在ECMAScript里包含下划线,(\w+)的贪婪匹配会把模式里的下划线也吃掉,导致后面的_(\d+)抓不到数字 - 改成非贪婪的
(\w+?)后,你误以为每个字符会被单独捕获,但其实(\w+?)还是会把连续匹配的内容放到同一个分组里
解决办法
办法1:限定前缀只匹配字母数字(最稳妥)
如果你的前缀部分本来就不该包含下划线,直接把(\w+)换成([^\W_]+)(等价于[A-Za-z0-9]+),这样前缀不会碰下划线,自然不会抢后面的_(\d+)的匹配机会:
const regex = /(label(:|\+))?([^\W_]+)(?:_(\d+))?/gi;
举个例子:
- 匹配
abc_123.def时,捕获组3是abc,捕获组4是123 - 匹配
label:xyz时,捕获组1是label:,捕获组3是xyz
办法2:允许前缀含下划线,用非贪婪匹配(纠正你的误解)
如果前缀可以包含下划线,那用(\w+?)完全没问题,它不会把每个字符单独捕获,而是把连续匹配到的所有内容放到同一个分组里。非贪婪只是让它匹配到刚好能让后面的_(\d+)匹配到的位置就停,不会贪多:
const regex = /(label(:|\+))?(\w+?)(?:_(\d+))?/gi;
比如匹配abc_def_456时,捕获组3是abc_def,捕获组4是456,完全符合需求。
办法3:用负向预查保住贪婪匹配
要是你非得用贪婪匹配,那就加个负向预查(?!_\d),确保\w+匹配的内容后面不会紧跟着“下划线+数字”,这样它就不会把结尾的下划线吃掉:
const regex = /(label(:|\+))?(\w+)(?!_\d)(?:_(\d+))?/gi;
内容的提问来源于stack exchange,提问作者cristian
相关产品推荐
相关产品推荐

