Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么re.sub(';*?';';-';';abc';)返回'-a-b-c-';而不是'-------';?_Python_Regex - Fatal编程技术网

Python 为什么re.sub(';*?';';-';';abc';)返回'-a-b-c-';而不是'-------';?

Python 为什么re.sub(';*?';';-';';abc';)返回'-a-b-c-';而不是'-------';?,python,regex,Python,Regex,这是python2.7的结果 >>> re.sub('.*?', '-', 'abc') '-a-b-c-' 我认为的结果应该如下 >>> re.sub('.*?', '-', 'abc') '-------' 但事实并非如此。为什么?您确定正确解释了的文档吗 *?,+?,??的“,”+”和“?”限定符都是贪婪的;它们匹配尽可能多的文本。有时这种行为是不可取的;如果 RE与'title'匹配,它将与 整个字符串,而不仅仅是'。在限定符后添加“?” 使其以非

这是python2.7的结果

>>> re.sub('.*?', '-', 'abc')
'-a-b-c-'
我认为的结果应该如下

>>> re.sub('.*?', '-', 'abc')
'-------'

但事实并非如此。为什么?

您确定正确解释了的文档吗

*?
+?
??
的“,”+”和“?”限定符都是贪婪的;它们匹配尽可能多的文本。有时这种行为是不可取的;如果 RE与
'title'
匹配,它将与 整个字符串,而不仅仅是
'
。在限定符后添加“?” 使其以非贪婪或最小的方式执行匹配;少 将尽可能匹配字符。使用。*?在过去 表达式将仅与“”匹配

添加
会将表达式转换为非贪婪表达式

贪婪:

re.sub(".*", "-", "abc")
re.sub(".*?", "-", "abc")
非贪婪:

re.sub(".*", "-", "abc")
re.sub(".*?", "-", "abc")
更新:FWIW
re.sub
做的正是它应该做的:

>>> from re import sub
>>> sub(".*?", "-", "abc")
'-a-b-c-'
>>> sub(".*", "-", "abc")
'-'
请参阅@BrenBarn关于为什么会得到
-a-b-c-
:)的精彩答案

下面是正在发生的事情的视觉表现:

.*?


对于新编辑的问题:

*?
可以匹配任意数量的字符,包括零。因此,它所做的是在字符串的每个位置匹配零个字符:在“a”之前,在“a”和“b”之间,等等。它用连字符替换这些零宽度匹配,给出您看到的结果


正则表达式不尝试逐个匹配每个字符;它尝试在字符串中的每个位置匹配。您的正则表达式允许它匹配零个字符。因此,它在每个位置匹配零,然后移动到下一个位置。您似乎认为在像“abc”这样的字符串中,“b”前面有一个位置,“b”里面有一个位置,“b”后面有一个位置,但在单个字符中没有“内部”位置。如果它匹配从“b”开始的零个字符,那么接下来它将尝试匹配从“b”开始的字符。你不可能让一个正则表达式在一个三个字符的字符串中匹配七次,因为只有四个位置可以匹配。

我所知道的关于这种行为的最好解释来自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
有些不标准,之所以保留它,可能仅仅是因为向后兼容性问题。(使用
re.split
)。

要详细说明,不同的实现在FindAll(或ReplaceAll)操作中对零宽度匹配有不同的处理。在不同的实现中可以观察到两种行为,Python
re
只是选择跟随第一行实现

1.在零宽度匹配时始终沿一个字符进行凹凸 在Java和JavaScript中,零宽度匹配会导致索引向前移动一个字符,因为保持在同一个索引将导致FindAll或ReplaceAll操作中出现无限循环

因此,在这种实现中,FindAll操作的输出最多可以包含一个从特定索引开始的匹配

默认的Python
re
包可能也遵循相同的实现(Ruby似乎也是如此)

2.在同一索引的下一个匹配中不允许零宽度匹配 在PHP中,它在PCRE libreary上提供了一个包装器,零宽度匹配不会导致索引立即跳转。相反,它将设置一个标志(
PCRE\u NOTEMPTY
),要求下一个匹配(从同一索引开始)为非零宽度匹配。如果匹配成功,它将沿着匹配长度(非零)移动;否则,它将以一个字符的速度前进

顺便说一下,PCRE库不提供内置的FindAll或ReplaceAll操作。它实际上是由PHP包装器提供的

因此,在这种实现中,FindAll操作的输出最多可以包含从同一索引开始的2个匹配项

Python
regex
包可能遵循以下实现路线


这一行实现更加复杂,因为它需要FindAll或ReplaceAll的实现来保持一个额外的状态,即是否不允许零宽度匹配。开发人员在使用低级匹配API时,还需要跟踪这些额外标志。

您现在已经对您的问题进行了相当大的更改。为什么您希望它产生这样的结果?@BrenBarn因为
匹配任何字符,为什么它不将“a”、“b”和“c”替换为“-”,而只将零字符替换为“-”?既然“.”匹配任何字符,为什么它不替换“a”,“b”和“c”改为“-”,只将零宽度字符改为“-?”@thuzhf:我在回答中加了一点<代码>可以匹配任何字符,但您允许它匹配零,因此它可以匹配零。在单个字符的“内部”没有位置可供匹配。如果它在“b”之前找到匹配项,则会尝试在“b”之后找到一个匹配项。如果你想让它匹配“b”,你必须让正则表达式使用“b”,而不是什么都不匹配。@thuzhf:我不明白你在问什么。忽略这个评论。谢谢你的解释!这与
re完全不同<