为什么这个正则表达式匹配两个连续的单词不起作用?

问题描述 投票:2回答:5

这里有一个类似的问题:Regular Expression For Consecutive Duplicate Words。这解决了如何解决这个问题的一般问题,而我正在寻找有关我的解决方案不起作用的具体建议。

我正在使用python正则表达式,我正在尝试匹配所有连续重复的单词,例如粗体:

我正努力做到这一点

我试过了:

[A-Za-z0-9]* {2}

这是正则表达式选择背后的逻辑:'[A-Za-z0-9]*'应该匹配任何长度的任何单词,而'[A-Za-z0-9]* '使它考虑单词末尾的空格。因此,[A-Za-z0-9]* {2}应标记前一个单词的重复,并在末尾添加一个空格。换句话说,它说“对于任何一个词,找到一个空格后立即重复的情况”。

我的逻辑在这里有什么缺陷?为什么这个正则表达式不起作用?

python regex
5个回答
5
投票
[A-Za-z0-9]* {2}

正则表达式中的量词将始终仅应用于它们前面的元素。因此,\d+将寻找一个或多个数字,但x\d+将寻找单个x,然后是一个或多个数字。

如果您希望量词不仅仅适用于单一事物,您需要先对其进行分组,例如: (x\d)+。这是一个捕获组,因此它实际上会在结果中捕获它。如果您只想将事物分组以应用通用量词,这有时是不受欢迎的。在这种情况下,您可以在组前面添加?:,使其成为非捕获组:(?:x\d)+

所以,回到你的正则表达式,你必须这样做:

([A-Za-z0-9]* ){2}

但是,这实际上并没有检查第二个匹配的单词是否与第一个相同。如果你想匹配,你需要使用反向引用。反向引用允许您引用表达式中先前捕获的组,再次查找它。在您的情况下,这将是这样的:

([A-Za-z0-9]*) \1

\1将引用第一个捕获组,即([A-Za-z0-9]*)。所以小组将匹配第一个单词。然后,有一个空格,然后再次对第一个单词进行反向引用。因此,这将寻找由空格分隔的相同单词的重复。


正如博评泡泡在评论中指出的那样,仍然有很多人可以做些来改善正则表达式。虽然我主要关心的是解释各种概念而不过多关注你的特定例子,但我想我仍然欠你一个更健壮的正则表达式,用于匹配一个由空格分隔的字符串中的两个连续单词。这是我的看法:

\b(\w+)\s\1\b

有一些与前一种方法不同的东西:首先,我正在寻找整个表达式的单词边界。当一个单词开始或结束时,\b基本匹配。这将阻止表达式在其他词语中匹配,例如, foo fooofoo oo都不匹配。

然后,正则表达式至少需要一个字符。所以空话不会匹配。我也在这里使用\w,这是一种包含字母数字字符的更灵活的方式。最后,我不是寻找实际的空间,而是接受单词之间的任何空格,所以这甚至可以匹配制表符或换行符。在那里添加量词也是有意义的,即\s+允许多个空白字符。

当然,这对你来说效果更好,取决于你的实际要求,我们将无法从你的一个例子中说出来。但这应该给你一些关于如何至少继续的想法。


3
投票

您可以将先前的捕获组与\1匹配为第一组,\2匹配第二组,等等...

import re
s = "I am struggling to to make this this work"
matches = re.findall(r'([A-Za-z0-9]+) \1', s)
print(matches)

>>> ['to', 'this']

如果您想要两次出现,请在\1周围添加一个捕获组:

matches = re.findall(r'([A-Za-z0-9]+) (\1)', s)
print(matches)

>>> [('to', 'to'), ('this', 'this')]

2
投票

一眼就看出这将匹配任何两个单词,而不是重复的单词。如果我没记错,星号(*)会匹配零次或多次,所以也许你应该使用加号(+)表示一个或多个。然后,您需要提供捕获并重新使用捕获的结果。此外,为清楚起见,\w可用于字母数字字符。此外,\b可用于匹配单词边界处的空字符串。

以下示例中的某些内容将帮助您完成部分工作。

>>> import re
>>> p = re.compile(r'\b(\w+) \1\b')
>>> p.findall('fa fs bau saa saa fa bau eek mu muu bau')
['saa']

这些页面可能会提供一些指导:


1
投票

这应该工作:\b([A-Za-z0-9]+)\s+\1\b

\b匹配单词边界,\s匹配空格,\1指定第一个捕获组。

>>> s = 'I am struggling to to make this this work'
>>> re.findall(r'\b([A-Za-z0-9]+)\s+\1\b', s)
['to', 'this']

1
投票

这是一个不使用RegEx的简单解决方案。

sentence = 'I am struggling to to make this this work'

def find_duplicates_in_string(words):
    """ Takes in a string and returns any duplicate words
        i.e. "this this"
    """
    duplicates = []
    words = words.split()

    for i in range(len(words) - 1):
        prev_word = words[i]
        word = words[i + 1]
        if word == prev_word:
            duplicates.append(word)
    return duplicates

print(find_duplicates_in_string(sentence)) 
© www.soinside.com 2019 - 2024. All rights reserved.