重复单词的正则表达式

我是一个正则表达式的新手,我不知道如何编写一个正则表达式来“匹配”任何重复的连续单词,比如:

春天的巴黎。

那个无关。

你笑什么? 我的天正则表达式有那么糟糕吗? ?

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

144265 次浏览

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

试试这个正则表达式:

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

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

Regex101例子 给你

广泛使用的 PCRE 库可以处理这样的情况(但是,与 POSIX 兼容的正则表达式引擎不能实现 ) :

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

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

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

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

Javascript 中的例子: 好的部分可以被修改来做到这一点:

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

B 使用 w 表示单词边界,其中 w 等价于[0-9A-Z _ a-z ]。如果你不介意这个限制,接受的答案是好的。

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

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

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

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

这个表达式(灵感来自上面的 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

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

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

试试下面的 RE

  • 单词边界的开头
  • W + 任意单词字符
  • 已经匹配了一个相同的单词
  • 说完了
  • () * 重复

    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();
    }
    

由于一些开发人员来到这个页面是为了寻找一种解决方案,这种解决方案不仅消除了重复的连续的非空格子字符串,而且还消除了重复的子字符串和其他子字符串,因此我将展示适当的模式。

模式: /(\b\S+)(?:\s+\1\b)+/(模式演示)
替换: $1(用捕获组 # 1替换全字符串匹配)

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

具体来说:

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

* 注意如果你处理的是带标点符号的句子或输入字符串,那么模式需要进一步改进。

下面是一个可以多次捕捉多个单词的程序:

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

正则表达式到条带2 + 重复单词(连续/非连续单词)

尝试这个正则表达式,可以捕捉2个或更多重复的单词,只留下一个单词。还有重复的单词 甚至不需要是连续的

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

在这里,\b用于单词边界,?=用于正向前看,\1用于反向引用。

例子 来源

下面的表达式应该能够正确地找到任意数量的重复单词。匹配可能不区分大小写。

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));
}

示例输入: 再见,再见,再见

样本输出: 再见

说明:

Regex 表达式:

B: 单词边界的开头

W + : 任意数量的单词字符

(s + 1 b) * : 后跟与前一个单词相匹配并结束单词边界的任意数量的空格。用 * 包裹整个东西有助于找到不止一次的重复。

分组:

Group (0) : 将包含上面的匹配组

Group (1) : 应包含上面大小写中匹配模式的第一个单词,再见

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

试试这个正则表达式,它适用于所有重复单词的情况:

\b(\w+)\s+\1(?:\s+\1)*\b

我认为另一种解决方案是像这样使用 命名捕获组和反向引用:

.* (?<mytoken>\w+)\s+\k<mytoken> .*/

或者

.*(?<mytoken>\w{3,}).+\k<mytoken>.*/

Kotlin logo科特林:

val regex = Regex(""".* (?<myToken>\w+)\s+\k<myToken> .*""")
val input = "This is a test test data"
val result = regex.find(input)
println(result!!.groups["myToken"]!!.value)

Java logoJava:

var pattern = Pattern.compile(".* (?<myToken>\\w+)\\s+\\k<myToken> .*");
var matcher = pattern.matcher("This is a test test data");
var isFound = matcher.find();
var result = matcher.group("myToken");
System.out.println(result);

JavaScript logoJavaScript:

const regex = /.* (?<myToken>\w+)\s+\k<myToken> .*/;
const input = "This is a test test data";
const result = regex.exec(input);
console.log(result.groups.myToken);


// OR


const regex = /.* (?<myToken>\w+)\s+\k<myToken> .*/g;
const input = "This is a test test data";
const result = [...input.matchAll(regex)];
console.log(result[0].groups.myToken);

所有这些都将 test检测为重复单词。
使用 Kotlin 1.7.0-Beta,Java 11,Chrome 和 Firefox 100进行测试。