python re.sub的行为在3.7中发生了更改。虫子还是虫子?

python re.sub的行为在3.7中发生了更改。虫子还是虫子?,python,regex,python-3.x,Python,Regex,Python 3.x,我的一个python脚本在最近的版本中开始出现错误。我追踪到了一个在python=3.7中表现不同的re替换,较新的python版本将替换两次 pythonre中有什么东西坏了吗?还是我做错了什么,最后被抓住了 据我所知,下面示例代码中的regexr'[^\u]*$”应该匹配最后一个下划线之后的所有内容。。。如果没有下划线,则为整个字符串 在下面的示例中,Python3.6创建s==“a_Z”,而Python3.7创建“a_ZZ” $ docker run --rm python:3.6-al

我的一个python脚本在最近的版本中开始出现错误。我追踪到了一个在python=3.7中表现不同的
re
替换,较新的python版本将替换两次

python
re
中有什么东西坏了吗?还是我做错了什么,最后被抓住了

据我所知,下面示例代码中的regex
r'[^\u]*$”
应该匹配最后一个下划线之后的所有内容。。。如果没有下划线,则为整个字符串

在下面的示例中,Python3.6创建s==“a_Z”,而Python3.7创建“a_ZZ”

$ docker run --rm  python:3.6-alpine python -c "import re;s=re.sub(r'[^_]*$','Z','a_b');assert s == 'a_Z',s"

$ docker run --rm  python:3.7-alpine python -c "import re;s=re.sub(r'[^_]*$','Z','a_b');assert s == 'a_Z',s"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError: a_ZZ
$docker-run--rm-python:3.6-alpine-python-c“导入re;s=re.sub(r'[^.]*$,'Z','a_b');断言s=='a_Z',s”
$docker run--rm python:3.7-alpine python-c“导入re;s=re.sub(r'[^.]*$','Z','a_b');断言s=='a_Z',s”
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
断言错误:a_ZZ
与3.8-alpine、3.9-rc-buster的错误相同。

根据:

在版本3.7中更改:当与以前的非空匹配相邻时,将替换模式的空匹配

'a_b'
中有两个匹配的模式,因为模式包括
*
b
;然后是一根空火柴。您可以在中看到这一点,例如,或使用
re.findall

>>> re.findall(r'[^_]*$', 'a_b')
['b', '']
如果切换到
+
,您将获得预期结果。

根据:

在版本3.7中更改:当与以前的非空匹配相邻时,将替换模式的空匹配

'a_b'
中有两个匹配的模式,因为模式包括
*
b
;然后是一根空火柴。您可以在中看到这一点,例如,或使用
re.findall

>>> re.findall(r'[^_]*$', 'a_b')
['b', '']

如果您切换到
+
,您将得到预期的结果。

中有几个“在版本3.7中进行了更改”,您查看了吗?中有几个“在版本3.7中进行了更改”,您查看了吗?@MarkBorgerding有意义,任何删除或忽略空匹配项的操作。因此,看起来re.sub现在很容易出错,因为模式可以匹配空字符串。将
count=1
添加到re.sub会限制替换,但是如果您不想替换空匹配项,是否有办法知道其中一个subst将最长(即不是空字符串),编写不提供空匹配的模式(正如我在回答中所建议的,
r'[^\u]+$'
可以工作)。我不会将其描述为容易出错,这一更改是一个错误修复。其基本原理是@MarkBorgerding,任何删除或忽略空匹配的内容都是有意义的。因此,看起来re.sub现在非常容易出错,模式可以匹配空字符串。添加
count=1
到re.sub会限制替换,但是,如果您不想替换空匹配项,那么有没有办法知道一个subst将是最长的(即不是空字符串),请编写不提供空匹配项的模式(正如我在回答中所建议的,
r'[^\u]+$”
)。我不会把它描述为容易出错的,这种更改是一个错误修复