为什么正则表达式的分支顺序会影响re.match的分词运行结果?
根因分析
核心问题出在正则表达式的分支左优先匹配规则,以及可空匹配项的摆放位置:
- 正则的
|分支运算符会从左到右依次尝试匹配,只要第一个分支匹配成功,就会跳过后续所有分支的校验。 - 无法正常运行的模式串中,第二捕获组的分支顺序为
([a-z])*|[0-9]|\(|\)|\*|\/:
其中第一个分支([a-z])*的量词*代表匹配0次或多次小写字母,也就是说即使当前位置没有小写字母,这个分支也能匹配到长度为0的空串,直接判定匹配成功。
当解析的字符串开头是括号、数字、运算符这类非小写字母的内容时,正则会直接命中第一个分支的空匹配,不会再尝试后面匹配括号、数字的分支。 - 这种情况下每次匹配得到的
m.group(0)总长度为0,执行s = s[len(m.group(0)):]后字符串完全没有变化,永远触发不了s == ''的结束条件,自然就会陷入死循环。
调整位置后正常运行的原因
调整后的模式串把([a-z])*放到了所有分支的最后:[0-9]|\(|\)|\*|\/|([a-z])*
此时正则会先尝试匹配数字、括号、运算符这些固定符号,只有当这些都匹配失败时,才会走最后一个小写字母的分支,不会出现有效字符被空匹配跳过的情况,自然就不会卡死。
额外优化提示:
- 当前数字规则只能匹配单个数字,比如
123会被拆分为['1','2','3'],可以把数字规则改为[0-9]+匹配连续数字- 你最初的错误规则末尾多了一个悬空的
|,会额外新增一个空匹配分支,也会加重死循环问题
内容的提问来源于stack exchange,提问作者Chase Blakey
相关产品推荐
相关产品推荐

