Python 正则表达式模块与 re 模块 - 模式不匹配



更新:此问题已由开发人员在提交 be893e9中解决

如果遇到相同的问题,请更新regex模块。
您需要版本2017.04.23或更高版本。


正如这个答案所指出的,我需要这个正则表达式

(?i)b((w{1,3})(-|.{2,10})[t ]?)+(2w{2,})

也使用regex模块...

import re     # standard library
import regex  # https://pypi.python.org/pypi/regex/
content = '"Erm....yes. T..T...Thank you for that."'
pattern = r"(?i)b((w{1,3})(-|.{2,10})[t ]?)+(2w{2,})"
substitute = r"2-4"
print(re.sub(pattern, substitute, content))
print(regex.sub(pattern, substitute, content))

输出:

"Erm....yes. T-Thank you for that."
"-yes. T..T...Thank you for that."

问:我必须如何编写此正则表达式以使regex模块以与re模块相同的方式对其进行反应?

使用re模块不是一种选择,因为我需要具有动态长度的后视。

澄清一下:如果正则表达式可以同时使用这两个模块,那就太好了,但最终我只需要它来regex

似乎这个错误与回溯有关。当捕获组重复时,会发生此问题,并且捕获组匹配,但组之后的模式不匹配。

举个例子:

>>> regex.sub(r'(?:(d{1,3})x)+', r'1', '123x5')
'5'

作为参考,预期输出为:

>>> re.sub(r'(?:(d{1,3})x)+', r'1', '123x5')
'1235'

在第一次迭代中,捕获组(d{1,3})使用前 3 位数字,x使用以下"x"字符。然后,由于+,比赛被第二次尝试。这一次,(d{1,3})匹配"5",但x不匹配。但是,捕获组的值现在(重新)设置为空字符串,而不是预期的123

作为解决方法,我们可以阻止捕获组匹配。在这种情况下,将其更改为(d{2,3})足以绕过该错误(因为它不再与"5"匹配):

>>> regex.sub(r'(?:(d{2,3})x)+', r'1', '123x5')
'1235'

至于所讨论的模式,我们可以使用前瞻断言;我们将(w{1,3})更改为(?=w{1,3}(?:-|..))(w{1,3})

>>> pattern= r"(?i)b((?=w{1,3}(?:-|..))(w{1,3})(-|.{2,10})[t ]?)+(2w{2,})"
>>> regex.sub(pattern, substitute, content)
'"Erm....yes. T-Thank you for that."'

编辑:该错误现已在正则表达式 2017.04.23 中解决

刚刚在 Python 3.6.1 中进行了测试,原始模式在reregex中的工作方式相同


原始解决方法 - 您可以使用惰性运算符+?(即在T...Tha....Thank等边缘情况下行为与原始模式不同的不同正则表达式):

pattern = r"(?i)b((w{1,3})(-|.{2,10})[t ]?)+?(2w{2,})"


2017.04.05 中的错误是由于回溯造成的,如下所示:

不成功的较长匹配会创建空的2组,从概念上讲,它应该触发回溯到较短的匹配,其中嵌套组不会为空,但regex似乎"优化"并且不会从头开始计算较短的匹配,而是使用一些缓存的值,忘记撤消嵌套匹配组的更新。

贪婪匹配示例((w{1,3})(.{2,10})){1,3}将首先尝试 3 次重复,然后回溯到更少:

import re
import regex
content = '"Erm....yes. T..T...Thank you for that."'
base_pattern_template = r'((w{1,3})(.{2,10})){%s}'
test_cases = ['1,3', '3', '2', '1']
for tc in test_cases:
pattern = base_pattern_template % tc
expected = re.findall(pattern, content)
actual = regex.findall(pattern, content)
# TODO: convert to test case, e.g. in pytest
# assert str(expected) == str(actual), '{}nexpected: {}nactual: {}'.format(tc, expected, actual)
print('expected:', tc, expected)
print('actual:  ', tc, actual)

输出:

expected: 1,3 [('Erm....', 'Erm', '....'), ('T...', 'T', '...')]
actual:   1,3 [('Erm....', '', '....'), ('T...', '', '...')]
expected: 3 []
actual:   3 []
expected: 2 [('T...', 'T', '...')]
actual:   2 [('T...', 'T', '...')]
expected: 1 [('Erm....', 'Erm', '....'), ('T..', 'T', '..'), ('T...', 'T', '...')]
actual:   1 [('Erm....', 'Erm', '....'), ('T..', 'T', '..'), ('T...', 'T', '...')]

最新更新