查找连续重复单词时的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后视正则表达式“固定宽度模式”错误的主要内容,如果未能解决你的问题,请参考以下文章

使用正则表达式从文本中删除连续重复的单词并显示新文本

book_精通正则表达式

正则表达式:向后看以避免奇数个连续的反斜杠

python 正则表达式

Java 正则表达式的后视组在附近没有明显的最大长度

在 Python 中使用正则表达式查找和替换文件中的单词列表