在使用贪婪字符时,re可以找到最小匹配吗?

7 投票
4 回答
15370 浏览
提问于 2025-04-15 14:21

免责声明:我不是正则表达式的专家。

我正在使用Python的re模块对很多html文件进行正则匹配。其中一个匹配模式大概是这样的:

<bla><blabla>87765.*</blabla><bla>

我遇到的问题是,它并没有找到所有(比如说)五个匹配的地方,而只找到一个。因为它把所有的匹配结果合并成了一个,使用了第一个匹配中的<bla><blabla>87765部分和最后一个匹配中的</blabla><bla>部分。

有没有办法让re找到最小的匹配呢?

4 个回答

1
I believe the regex
<bla><blabla>87765.*?</blabla><bla>
can produce catastrophic backtracking.

Instead, use:
<bla><blabla>87765[^<]*</blabla><bla>

Using atomic grouping (I'm not sure Python supports this), 
the above regex becomes 
<bla><blabla>(?>(.*?<))/blabla><bla>

在正则表达式中,括号内的内容(像 (?> ... ) 这样的)会被当作一个整体来处理。一旦正则引擎离开这个括号里的内容,它就把这个整体当成一个单独的“标记”。因为这个整体是一个标记,所以一旦找到了匹配的内容,就不能再回头去检查之前的部分了。如果需要回头检查,正则引擎只能回到这个整体之前的标记(在我们的例子中就是那个“^”符号)。如果在这个整体前面没有其他标记,正则就必须从字符串的下一个位置重新开始匹配。值得注意的是,我需要在这个整体里加上“<”符号,以确保它的原子性。差不多就是这样。

5

Python的re模块支持非贪婪匹配。你只需要在通配符模式的末尾加一个?,比如.*?。想了解更多,可以查看这个教程

19

你可以在你的模式中使用一种叫做“懒惰限定符”的东西(想了解更多,可以参考Python文档,里面有关于*?+???的详细说明):

<bla><blabla>87765.*?</blabla><bla>

或者,你可以把<从可能匹配的字符中排除掉:

<bla><blabla>87765[^<]*</blabla><bla>

只有<blabla></blabla>之间没有子标签的情况下。

撰写回答