重复单词的正则表达式


114

我是一个正则表达式新手,我还不太清楚如何编写一个可以与任何重复的连续单词“匹配”的正则表达式,例如:

在巴黎的的春天。

并不是说这有关。

你笑什么?是我的我的正则表达式不好?

是否有一个单个正则表达式将与上面的所有粗体字符串匹配?


4
@poly:那不是“指责”,而是一个冷静,正常的问题,完全可以用“否”作为答案。@Joshua:是的,有些人(不少)让这个网站为他们做功课。但是,在这样标记作业时,问作业问题对SO来说并不是一件坏事。通常,答案的样式从“这是解决方案”变为“这是您未曾想到的某些事情”,这是一件好事。有人必须努力保持这种区别,在他的情况下是我,而在其他地方,“其他人”也做同样的事情。就这样。
Tomalak 2010年

13
希望永远不要看到这样的问题:“这听起来有点像工作场所的问题。是吗?” 然后人们会争论堆栈溢出是否正在完成某人的工作。
marcio 2014年

关于您接受的正则表达式解决方案,@ Joshua +1,能否请您告诉我如何用对中的一个替换匹配(重复项)(例如not that that is related-> not that is related)?在此先感谢
Antoine

@Joshua我想我找到了解决方案:我应该替换为\1
Antoine

2
@DavidLeal怎么样\b(\w+)\s+(\1\s*)+\b
ytu

Answers:


140

试试这个正则表达式:

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

\b是单词边界,它\1引用的是第一组捕获的匹配项。


1
我好疑惑; 有可能这样做\0吗?(哪里\0是整个正则表达式,直到当前点,还是\0指整个正则表达式)
Pindatjuh 2010年

@Pindatjuh:不,我不这么认为,因为该子比赛也将是整个比赛的一部分。
浓汤

至少可以在Eclipse搜索/替换对话框中使用的正则表达式引擎上工作。
Chaos_99

3
只是警告,它不处理带有撇号或(如Noel提到的)连字符的单词。在这种情况下,Mike的解决方案效果更好

3
此外,它不会捕获三重(或更多),而不是当重复/三重之一位于字符串末尾时
Nico

20

我相信此正则表达式可以处理更多情况:

/(\b\S+\b)\s+\b\1\b/

可以在这里找到测试字符串的很好选择:http : //callumacrae.github.com/regex-tuesday/challenge1.html


很好,可以使用撇号/连字符/等。也是-谢谢!

对于challenge1链接,您要放置在replace区域中以使用分组词吗?尝试过<strong>\0</strong>但不起作用。
uptownhr '16

2
它不会捕获三重(或更多),而不是当重复/三重之一在字符串的末尾时
Nico

@uptownhr您要使用$1 <strong>$2</strong>。还要使用不同的正则表达式/\b(\S+) (\1)\b/gi。这是链接:callumacrae.github.io/regex-tuesday/…–
dsalaj

如果我想从特定标签中查找所有连续的单词,例如<p class="bebe">bla bla</p>如何集成此正则表达式公式?
Just Me

7

尝试以下RE

  • \ b词的开始词边界
  • \ W +任何单词字符
  • \ 1个相同的单词已经匹配
  • \ b字尾
  • ()*再次重复

    public static void main(String[] args) {
    
        String regex = "\\b(\\w+)(\\b\\W+\\b\\1\\b)*";//  "/* Write a RegEx matching repeated words here. */";
        Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE/* Insert the correct Pattern flag here.*/);
    
        Scanner in = new Scanner(System.in);
    
        int numSentences = Integer.parseInt(in.nextLine());
    
        while (numSentences-- > 0) {
            String input = in.nextLine();
    
            Matcher m = p.matcher(input);
    
            // Check for subsequences of input that match the compiled pattern
            while (m.find()) {
                input = input.replaceAll(m.group(0),m.group(1));
            }
    
            // Prints the modified sentence.
            System.out.println(input);
        }
    
        in.close();
    }

5

广泛使用的PCRE库可以处理这种情况(你不会达到的了与POSIX兼容的正则表达式引擎一样,虽然):

(\b\w+\b)\W+\1

您需要一些东西来匹配两个单词之间的字符,例如\W+\b不会这样做,因为它不会消耗任何字符。
艾伦·摩尔

在的情况下,这可能会导致假阳性匹配... the these problems...。该解决方案不如足以实现单词边界的Gumbo模式的一般结构可靠。
mickmackusa

如果我想从特定标签中查找所有连续的单词,例如<p class="bebe">bla bla</p>如何集成此正则表达式公式?
Just Me

4

这是我用来删除twitch机器人中重复短语的正则表达式:

(\S+\s*)\1{2,}

(\S+\s*) 查找不是空格的任何字符串,后跟空格。

\1{2,}然后在字符串中查找该短语的两个以上实例以进行匹配。如果有3个相同的词组,则匹配。


这个答案是误导的。它不搜寻重复项,而是搜寻3次或更多次出现的子串。由于\s*捕获组中的,它也不是很健壮。观看此演示:regex101.com/r/JtCdd6/1
mickmackusa,

此外,极端情况(低频文本)将产生假阳性匹配。例如,I said "oioioi" that's some wicked mistressship!oioioisss
mickmackusa

4

下面的表达式应该可以正常工作以查找任意数量的连续单词。匹配可以不区分大小写。

String regex = "\\b(\\w+)(\\s+\\1\\b)*";
Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);

Matcher m = p.matcher(input);

// Check for subsequences of input that match the compiled pattern
while (m.find()) {
     input = input.replaceAll(m.group(0), m.group(1));
}

输入样本:再见再见GooDbYe

样本输出:再见

说明:

正则表达式:

\ b:单词边界的开始

\ w +:任意数量的单词字符

(\ s + \ 1 \ b)*:任意数量的空格,后跟与前一个单词匹配并结束单词边界的单词。用*包裹的整个内容有助于找到多个重复项。

分组:

m.group(0):在上述情况下将包含匹配的组再见再见GooDbYe

m.group(1):在上述情况下,再包含匹配模式的第一个单词再见

替换方法应将所有连续匹配的单词替换为单词的第一个实例。


3

不,那是不规则的语法。您可能会使用特定于引擎/语言的正则表达式,但是没有通用的正则表达式可以做到这一点。


12
尽管从严格意义上讲是正确的,但我相信不再有严重使用的正则表达式引擎不支持分组和反向引用。
Tomalak

3

这是一个可以多次捕获多个单词的单词:

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

如果我想从特定标签中查找所有连续的单词,例如<p class="bebe">bla bla</p>如何集成此正则表达式公式?
Just Me

我相信这将需要HTML解析。对于要搜索的任何给定标签,请在HTML中找到所有出现的标签,然后逐个运行此正则表达式。或者,如果您不关心重复出现在HTML中的何处,请连接所有标签文本属性,并在连接的字符串上运行regex
synaptikon

我找到了答案<p class="bebe">.*?\b\s+(\w+)\b\K\s+\1\s+\b(?=.*?<\/p>)
Just Me

3

正则表达式剥离2个以上重复的单词(连续/非连续单词)

尝试使用此正则表达式,它可以捕获2个或更多重复的单词,并且仅留下一个单词。并且重复的单词甚至不必是连续的

/\b(\w+)\b(?=.*?\b\1\b)/ig

在此,\b用于词边界,?=用于正向超前,并\1用于向后引用。

范例 来源


1
不连续是个坏主意:"the cat sat on the mat"->" cat sat on the mat"
沃尔夫(Walf)'18

@沃尔夫。但是,在某些情况下会这样做。(例如:在抓取数据时)
Niket Pathak '18

我更正后,为什么又重新破坏了正则表达式?你以为我改变了意图吗?即使您链接的示例也没有错误。
Walf

是的,这是一个错误,复制粘贴了错误的内容。打算从我的示例中实际复制一个。无论如何,现在可以使用了!一切都很好!谢谢!
Niket Pathak

2

可以使用Javascript中的示例:优良零件来做到这一点:

var doubled_words = /([A-Za-z\u00C0-\u1FFF\u2800-\uFFFD]+)\s+\1(?:\s|$)/gi;

\ b将\ w用于单词边界,其中\ w等效于[0-9A-Z_a-z]。如果您不介意该限制,则可接受的答案很好。


2

由于一些开发人员正在此页面上寻找一种解决方案,该解决方案不仅消除了重复的连续非空白子字符串,而且消除了三重复以及以后的内容,因此,我将展示适应的模式。

图案:/(\b\S+)(?:\s+\1\b)+/图形演示
替换:$1(与捕获组#替换fullstring匹配1)

此模式贪婪地匹配“整个”非空白子字符串,然后需要一个或多个匹配子字符串的副本,这些副本可以由一个或多个空白字符(空格,制表符,换行符等)分隔。

特别:

  • \b (单词边界)字符对于确保部分单词不匹配至关重要。
  • 第二个括号是一个非捕获组,因为不需要捕获此可变宽度子字符串-只需匹配/吸收即可。
  • +非捕获组上的(一个或多个量词)比*因为*“阻止”正则表达式引擎捕获和替换单例事件更合适-这是浪费的模式设计。

*请注意,如果您要处理带有标点符号的句子或输入字符串,则需要进一步完善模式。


@AdamJones在您的php项目中使用此模式。Nico的答案中包含一些不必要的语法。
mickmackusa

1

这个表达式(从上面的Mike那里得到启发)似乎捕获了所有重复项,三重复项等,包括字符串末尾的重复项,而大多数其他字符串却没有:

/(^|\s+)(\S+)(($|\s+)\2)+/g, "$1$2")

我知道这个问题要匹配重复项,但是一式三份只是彼此相邻的两个重复项:)

首先,我(^|\s+)确保它以一个完整的单词开头,否则“儿童牛排”将变为“儿童牛排”(“ s”将匹配)。然后,它匹配所有完整单词((\b\S+\b)),然后匹配字符串($)的末尾或多个空格(\s+),整个重复不止一次。

我这样尝试过,效果很好:

var s = "here here here     here is ahi-ahi ahi-ahi ahi-ahi joe's joe's joe's joe's joe's the result result     result";
print( s.replace( /(\b\S+\b)(($|\s+)\1)+/g, "$1"))         
--> here is ahi-ahi joe's the result

我在将其重写为PHP时遇到麻烦,至关重要的是,我得到了匹配重复项的单个副本,以替换每次出现的重复项/重复项等。到目前为止,我有:preg_replace('/(^ | \ s +)(\ S +)( ($ | \ s +)\ 2)+ / im','$ 0',$ string);
亚当·琼斯

这是最好的答案。我只是\b在结尾处做了些微调整,如下所示:/(^|\s+)(\S+)(($|\s+)\2)+\b/g, "$1$2")这将适用于以下情况:the the string String string stringing the the along the the string将变为the string stringing the along the stringNotice string stringing。它与您的答案相匹配。谢谢。
Ste

-1

如果要对重复的单词进行不区分大小写的检查,请使用此选项。

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

使用不区分大小写的模式修饰符对您的模式没有用。没有字母范围可以影响标志。
mickmackusa

这实际上是已接受答案的副本,并且没有为页面增加任何价值。请考虑删除此答案以减少页面膨胀。
mickmackusa '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.