在python 3.7中检索python 3.6处理re.sub()与零长度匹配

Gil*_*cas 6 python regex python-3.x python-3.6 python-3.7

使用python 3.7改变零长度匹配的处理.请考虑以下python 3.6(和之前的版本):

>>> import re
>>> print(re.sub('a*', 'x', 'bac'))
xbxcx
>>> print(re.sub('.*', 'x', 'bac'))
x
Run Code Online (Sandbox Code Playgroud)

我们使用python 3.7得到以下内容:

>>> import re
>>> print(re.sub('a*', 'x', 'bac'))
xbxxcx
>>> print(re.sub('.*', 'x', 'bac'))
xx
Run Code Online (Sandbox Code Playgroud)

我知道这是PCRE的标准行为.此外,re.finditer()似乎总是检测到额外的匹配:

>>> for m in re.finditer('a*', 'bac'):
...     print(m.start(0), m.end(0), m.group(0))
...
0 0
1 2 a
2 2
3 3
Run Code Online (Sandbox Code Playgroud)

也就是说,我有兴趣检索python 3.6的行为(这是一个在python中实现sed的业余爱好项目).

我可以提供以下解决方案:

def sub36(regex, replacement, string):

    compiled = re.compile(regex)

    class Match(object):
        def __init__(self):
            self.prevmatch = None
        def __call__(self, match):
            try:
                if match.group(0) == '' and self.prevmatch and match.start(0) == self.prevmatch.end(0):
                    return ''
                else:
                    return re._expand(compiled, match, replacement)
            finally:
                self.prevmatch = match

    return compiled.sub(Match(), string)
Run Code Online (Sandbox Code Playgroud)

这使:

>>> print(re.sub('a*', 'x', 'bac'))
xbxxcx
>>> print(sub36('a*', 'x', 'bac'))
xbxcx
>>> print(re.sub('.*', 'x', 'bac'))
xx
>>> print(sub36('.*', 'x', 'bac'))
x
Run Code Online (Sandbox Code Playgroud)

但是,这似乎非常适合这些例子.

使用python 3.7实现re.sub()零长度匹配的python 3.6行为的正确方法是什么?

小智 1

根据 3.7 新增内容,

可以通过将模式更改为 来恢复以前的行为r'.+'

请参阅https://docs.python.org/3/whatsnew/3.7.html下的“Python API 的更改”。因此,解决方案似乎是修改这样的正则表达式;似乎没有可以传递的标志re来请求此行为。