查找连续重复单词时的Python后视正则表达式“固定宽度模式”错误
Posted
技术标签:
【中文标题】查找连续重复单词时的Python后视正则表达式“固定宽度模式”错误【英文标题】:Python look-behind regex "fixed-width pattern" error while looking for consecutive repeated words 【发布时间】:2018-01-02 05:21:00 【问题描述】:我有一个文本,其中的单词由.
分隔,其中包含 2 个和 3 个连续重复的单词:
My.name.name.is.Inigo.Montoya.You.killed.my.father.father.father.Prepare.to.die-
我需要用正则表达式独立匹配它们,不包括三次重复的重复项。
因为有最大值。 3个连续重复的单词,这个
r'\b(\w+)\.+\1\.+\1\b'
成功捕获
father.father.father
但是,为了捕捉 2 个连续重复的单词,我需要确保下一个单词和上一个单词不一样。我可以做一个消极的前瞻
r'\b(\w+)\.+\1(?!\.+\1)\b'
但我对消极的后视
的尝试r'(?<!(\w)\.)\b\1\.+\1\b(?!\.\1)'
返回一个固定宽度的问题(当我保留+
时)或其他一些问题。
我应该如何纠正消极的后视?
【问题讨论】:
正如你已经说过的,如果匹配没有恒定的长度,你就不能使用lookbehinds。您可以使用regex
库,这是一个替代的正则表达式库,允许可变长度的后视。
可以用1个以上的点分隔部分吗?你用了\.+
,是有意的吗?见this demo,你在找这样的东西吗?
如果只是从“multicates”\b(\w+)(?:\.(\1)(?:\.\1)+|\.(\1))\b
中识别重复项,第 3 组中的匹配项是重复项,第 2 组中的匹配项是捕获词的三倍或更多。
【参考方案1】:
我认为可能有一种更简单的方法来捕捉你想要的东西,而无需消极的后视:
r = re.compile(r'\b((\w+)\.+\2\.+\2?)\b')
r.findall(t)
> [('name.name.', 'name'), ('father.father.father', 'father')]
只是将第三次重复设为可选。
捕获同一单词任意数量重复的版本可能如下所示:
r = re.compile(r'\b((\w+)(\.+\2)\3*)\b')
r.findall(t)
> [('name.name', 'name', '.name'), ('father.father.father', 'father', '.father')]
【讨论】:
为了拒绝匹配尾随点,您可以将第二个点放在非捕获组中。r'((\w+)\.+\2(?:\.+\2)?)'
.
除非我尝试错了,否则这些正则表达式似乎匹配重复项和三次项。我正在尝试找到不同的正则表达式来分别匹配重复项和三次项。【参考方案2】:
也许根本不需要正则表达式。
使用itertools.groupby
可以完成这项工作。 旨在将相同出现的连续项目分组。
tuple
值,仅当长度> 1 时才计数
像这样:
import itertools
s = "My.name.name.is.Inigo.Montoya.You.killed.my.father.father.father.Prepare.to.die"
matches = [(l[0],len(l)) for l in (list(v) for k,v in itertools.groupby(s.split("."))) if len(l)>1]
结果:
[('name', 2), ('father', 3)]
所以基本上我们可以对这个元组列表做任何我们想做的事情(例如根据出现的次数过滤它)
奖励(因为我一开始误读了这个问题,所以我把它留在里面):从句子中删除重复项 - 按单词分组(根据点拆分后),如上 - 只取列表 comp 中返回的值的键(值)(我们不需要这些值,因为我们不计算) - 用点加入回来
一行(仍在使用itertools
):
new_s = ".".join([k for k,_ in itertools.groupby(s.split("."))])
结果:
My.name.is.Inigo.Montoya.You.killed.my.father.Prepare.to.die
【讨论】:
可以丢next
,我认为k for k,_
也应该可以工作,因为关键是每个值。
谢谢!我不需要删除重复项,只是为了识别它们,但元组方法应该有效。我试试看!
@Jean-FrançoisFabre 这被证明是最简单的解决方案,所以在这种情况下我放弃了正则表达式。再次感谢!
你是个聪明人。复杂的正则表达式有时很难维护/修改。在像这样的简单情况下,它们并不是真正需要的(好吧,当你使用 python 时!)
啊,旧的'正则表达式在你有字符串拆分'参数时很愚蠢。 matches = [(l[0],len(l)) for l in (list(v) for k,v in itertools.groupby(s.split("."))) if len(l)>1]
比 \b((\w+)\.+\2\.+\2?)\b
更容易?!正则表达式也是跨平台的。此外,快速基准测试:10000 次循环,最好的 3 次:每个循环 4.04 µs | 10000 个循环,3 个循环中的最佳:每个循环 20.4 µs - 猜猜哪一个正在使用正则表达式。以上是关于查找连续重复单词时的Python后视正则表达式“固定宽度模式”错误的主要内容,如果未能解决你的问题,请参考以下文章