这是python2.7的结果。
>>> re.sub('.*?', '-', 'abc')
'-a-b-c-'
我认为的结果应如下。
>>> re.sub('.*?', '-', 'abc')
'-------'
但事实并非如此。为什么呢?
答案 0 :(得分:4)
我所知道的这种行为的最佳解释来自regex
PyPI包,它旨在最终替换re
(虽然它已经是这样的现在很久了。)
有时候不清楚应该如何处理零宽度匹配。例如,在匹配> 0个字符后,*。匹配0个字符吗?
大多数正则表达式实现遵循Perl(PCRE)的引导,但re模块有时不遵循。 Perl行为似乎是最常见的(并且re模块有时肯定是错误的),因此在版本1中,regex模块遵循Perl行为,而在版本0中,它遵循遗留的re行为。
示例:
# Version 0 behaviour (like re) >>> regex.sub('(?V0).*', 'x', 'test') 'x' >>> regex.sub('(?V0).*?', '|', 'test') '|t|e|s|t|' # Version 1 behaviour (like Perl) >>> regex.sub('(?V1).*', 'x', 'test') 'xx' >>> regex.sub('(?V1).*?', '|', 'test') '|||||||||'
(?VX)
在正则表达式中设置版本标志。第二个例子是你所期望的,并且据说是PCRE所做的。 Python的re
有点不标准,并且保留,因为它可能完全是由于向后兼容性问题。 I've found an example of something similar(与re.split
)。
答案 1 :(得分:3)
您确定正确解释了re.sub的文档吗?
*?
,+?
,??
&#39; &#39;,&#39; +&#39;和&#39;?& #39;资格赛都是贪心的;它们匹配尽可能多的文本。有时这种行为是不可取的;如果 RE&lt;。&gt;与'<H1>title</H1>'
匹配,它将匹配。{ 整个字符串,而不仅仅是'<H1>'
。添加&#39;?&#39;在资格赛之后 使它以非贪婪或极简的方式进行比赛;很少 尽可能匹配的字符。使用。*?在以前 表达式仅匹配&#39;。
添加?
会将表达式转换为非贪婪的表达式。
<强>贪婪:强>
re.sub(".*", "-", "abc")
<强>非贪婪:强>
re.sub(".*?", "-", "abc")
更新:FWIW re.sub
完全符合预期:
>>> from re import sub
>>> sub(".*?", "-", "abc")
'-a-b-c-'
>>> sub(".*", "-", "abc")
'-'
请参阅@ BrenBarn关于你获得-a-b-c-
的原因的精彩答案:)
这是对正在发生的事情的直观表达:
.*?
答案 2 :(得分:3)
对于您新编辑的问题:
.*?
可以匹配任意数量的字符,包括零。所以它的作用是匹配字符串中每个位置的零个字符:在“a”之前,在“a”和“b”之间,等等。它用连字符替换每个零宽度匹配,给出结果你看。
正则表达式不会尝试逐个匹配每个字符;它尝试匹配字符串中的每个位置。你的正则表达式允许它匹配零个字符。因此它在每个位置匹配零并继续下一个位置。你似乎在想,在像“abc”这样的字符串中,“b”之前有一个位置,“b”之内有一个位置,“b”之后有一个位置,但是里面没有位置“个性。如果它匹配在“b”之前开始的零个字符,则它尝试的下一个事项是匹配“b”之后的开始。在三个字符的字符串中,你无法使正则表达式匹配七次,因为只有四个位置匹配。
答案 3 :(得分:1)
详细说明Veedrac's answer,不同的实现在FindAll(或ReplaceAll)操作中对零宽度匹配有不同的处理方式。在不同的实现中可以观察到两种行为,Python re
只是选择遵循第一行实现。
在Java和JavaScript中,零宽度匹配会导致索引碰到一个字符,因为保留在同一索引中会导致FindAll或ReplaceAll操作中出现无限循环。
因此,此类实现中FindAll操作的输出最多可包含一个从特定索引开始的匹配。
默认的Python re
包可能也遵循相同的实现(Ruby似乎也是如此)。
在PHP中,它提供了一个基于PCRE库的包装器,零宽度匹配不会导致索引立即碰撞。相反,它将设置一个标志(PCRE_NOTEMPTY
),要求下一个匹配(从同一索引开始)为非零宽度匹配。如果匹配成功,它将沿着匹配的长度(非零)碰撞;否则,它会撞到一个角色。
顺便说一句,PCRE库不提供内置的FindAll或ReplaceAll操作。它实际上是由PHP包装器提供的。
因此,此类实现中FindAll操作的输出最多可包含2个从同一索引开始的匹配。
Python regex
包可能遵循这一实现方式。
这条实现更复杂,因为它需要实现FindAll或ReplaceAll以保持是否禁止零宽度匹配的额外状态。开发人员还需要在使用低级匹配API时跟踪这些额外标志。