【问题标题】:Python - error: look-behind requires fixed-width patternPython - 错误:后视需要固定宽度的模式
【发布时间】:2018-01-10 18:49:39
【问题描述】:

我有一个看起来像这样的字符串:

phrase = '5 hampshire road bradford on avon avon dinas powys powys north somerset hampshire avon'

我想返回一个删除了某些单词的新字符串,前提是它们前面没有某些其他单词。

例如,我要删除的单词是:

c_out = ["avon", "powys", "somerset","hampshire"]

只有在他们不关注的情况下

c_except = ["on\s","dinas\s"]

注意:c_out 中可能有多个单词实例,c_except 中可能有多个单词实例。

我个人尝试了'on\s'

phrase = '5 hampshire road bradford on avon avon dinas powys powys north somerset hampshire avon'

regexp1 = re.compile(r'(?<!on\s)(avon|powys|somerset|hampshire)')
print("1st Result: ", regexp1.sub('', phrase))
1st Result:  '5  road bradford on avon avon dinas   north'

这正确地忽略了第一个'avon',因为它前面是'on\s',它正确地删除了第三个'avon'但是它忽略了第二个'avon'(它没有删除)。

同理,对于'dinas\s'

phrase = '5 hampshire road bradford on avon avon dinas powys powys north somerset hampshire avon'

regexp2 = re.compile(r'(?<!dinas\s)(avon|powys|somerset|hampshire)')
print("2nd Result: ", regexp2.sub('', phrase))
2nd Result:  '5  road bradford on   dinas powys  north '

这会正确地忽略第一个'powys' 并删除第二个(注意'... powys north' 之间的双空格。

我尝试通过以下方式组合这两个表达式:

regexp3 = re.compile(r'((?!on\s)|(?!dinas\s))(avon|powys|somerset|hampshire)')
print("3rd Result: ", regexp3.sub('', phrase))
3rd Result:  5  road bradford on   dinas   north

这错误地删除了每个单词,并完全忽略了'on\s''dinas\s'

然后我尝试了:

regexp4 = re.compile(r'(?<!on\s|dinas\s)(avon|powys|somerset|hampshire)')
print("4th Result: ", regexp4.sub('', phrase))

得到:

error: look-behind requires fixed-width pattern

我想结束:

Result: '5  road bradford on avon dinas powys  north     '

我看过了:

Why is this not a fixed width pattern? Python Regex Engine - "look-behind requires fixed-width pattern" Error regex: string with optional parts

但无济于事。

我做错了什么?


来自 cmets:

regexp5 = re.compile(r'(?<!on\s)(?<!dinas\s)(avon|powys|somerset|hampshire)')
print("5th Result: ", regexp5.sub('', phrase))
5th Result:  5  road bradford on avon avon dinas powys  north 

这又错过了第二个雅芳。

【问题讨论】:

  • (?&lt;!on\s|dinas\s) 替换为(?&lt;!on\s)(?&lt;!dinas\s)
  • @WiktorStribiżew 忽略第二个 'avon' -> 5th result = "5 road bradford on avon avon dinas powys north "
  • 然后使用单词边界 - r'(?&lt;!\bon\s)(?&lt;!\bdinas\s)'
  • @WiktorStribiżew 这给了我原来的错误error: look-behind requires fixed-width pattern。 (见第 6 个正则表达式)
  • ideone.com/BSEojT。没有错误,结果符合预期。

标签: python regex python-3.x


【解决方案1】:

这里有两种方法可以解决这个问题:

链式后视

将一个基于交替的lookbehind转换成几个否定的lookbehind,因为它们之间的逻辑关系将是相同的(AND的逻辑关系):

import re
phrase = '5 hampshire road bradford on avon avon dinas powys powys north somerset hampshire avon'
c_except = [r"on\s",r"dinas\s"]
c_out = ["avon", "powys", "somerset","hampshire"]
rx = r"(?<!\b{0})({1})".format(r")(?<!\b".join(c_except), "|".join(c_out))
print(re.sub(rx, "", phrase))

this Python demo

捕捉接近

捕获您需要保留的内容并仅匹配您需要删除的内容,并使用 \1 反向引用恢复 Group 1 值:

import re
phrase = '5 hampshire road bradford on avon avon dinas powys powys north somerset hampshire avon'
c_except = [r"on\s+",r"dinas\s+"]
c_out = ["avon", "powys", "somerset","hampshire"]
rx = r"(\b(?:{0})(?:{1}))|(?:{1})".format(r"|".join(c_except), "|".join(c_out))
print(re.sub(rx, r"\1", phrase))

another Python demo

请注意,这种方法是有利的,因为您可以在 c_except 中使用可变宽度模式。

正则表达式看起来像

(\b(?:on\s+|dinas\s+)(?:avon|powys|somerset|hampshire))|(?:avon|powys|somerset|hampshire)

由于\b 字边界,它将匹配ondinas 作为整个单词,然后是您需要删除的任何术语,并且由于该部分被包装到捕获组中,您可以参考使用\1 反向引用捕获。在所有其他上下文中,c_out 术语将与 |(?:avon|powys|somerset|hampshire) 模式一起删除。

注意:\1 替换将在 Python 3.5+ 中工作。对于旧版本和 Python 2.x,您需要将其替换为 lambda:

re.sub(rx, lambda m: m.group(1) if m.group(1) else "", phrase)

【讨论】:

  • 谢谢 - 这确实有效。非常感谢有两种方法。再次感谢,C
猜你喜欢
  • 2021-02-21
  • 2020-02-07
  • 1970-01-01
  • 2011-02-06
  • 2014-07-09
  • 1970-01-01
  • 2018-01-02
  • 1970-01-01
相关资源
最近更新 更多