我该如何使用Perl正则表达式来查找重复字母?

24

我正在寻找一个正则表达式,可以找到重复出现的字母。例如,任何出现两次或更多的字母:

booooooot or abbott

我不会提前知道我要查找的信件。

这是我在面试中被问到的问题,也是我问其他人的问题。很少有人能回答正确。

11个回答

54

你可以找到任何一个字母,然后使用\1来再次查找该字母(或更多)。如果你只需要知道这个字母,那么$1将包含它。否则,你可以将第二次匹配的内容连接到第一次上。

my $str = "Foooooobar";

$str =~ /(\w)(\1+)/;

print $1;
# prints 'o'
print $1 . $2;
# prints 'oooooo'

只需将\w替换为[a-zA-Z]即可进行字母交换。 - TomC
现在我可以仅替换重复的字母:Regex.Replace(str, @"(\w)\1+", "$1"); 谢谢Adam。 - Junior Mayhé

14

我认为你实际上想要这个而不是"\w",因为它包括数字和下划线。

([a-zA-Z])\1+

好的,好的,我明白了Leon的意思。将其用于Unicode世界或POSIX相关内容。

([[:alpha:]])\1+

2
我们生活在一个Unicode的世界中。[a-zA-Z]无法涵盖大多数语言。[[:alpha:]]会更加准确。 - Leon Timmermans
哦,你们这些疯狂的外国人!;o)是的,Unicode会是非美式英语字符的更好语法。 - Keng

9

我认为使用反向引用会起作用:

(\w)\1+

\w基本上等同于[a-zA-Z_0-9],所以如果你只想匹配A到Z之间的字母(不区分大小写),请使用[a-zA-Z]

(编辑:或者,就像Tanktalus在他的评论中提到的那样(以及其他人已经回答的那样),[[:alpha:]],这是与语言环境有关的)


使用 [[:alpha:]] 而不是 [a-zA-Z],因为它是与语言环境相关的;-) - Tanktalus

6

使用\N来引用之前的组:

/(\w)\1+/g

4
你需要注意什么被认为是字母,这取决于你的语言环境。使用ISO Latin-1将允许匹配带重音的西方语言字符作为字母。在以下程序中,默认语言环境不识别é,因此créé无法匹配。取消注释语言环境设置代码,然后它开始匹配。
还要注意,\w包括数字和下划线字符以及所有字母。要仅获取字母,您需要取非字母数字和下划线字符的补集。这只留下字母。
将其构建为问题可能更容易理解:
“哪个正则表达式与除3之外的任何数字匹配?” 答案是: /[^\D3]/
#! /usr/local/bin/perl

use strict;
use warnings;

# uncomment the following three lines:
# use locale;
# use POSIX;
# setlocale(LC_CTYPE, 'fr_FR.ISO8859-1');

while (<DATA>) {
    chomp;
    if (/([^\W_0-9])\1+/) {
        print "$_: dup [$1]\n";
    }
    else {
        print "$_: nope\n";
    }
}

__DATA__
100
food
créé
a::b

3
以下代码将返回所有重复两次或更多次的字符:
my $str = "SSSannnkaaarsss";

print $str =~ /(\w)\1+/g;

2

只是为了好玩,完全不同的方法:

if ( ($str ^ substr($str,1) ) =~ /\0+/ ) {
    print "found ", substr($str, $-[0], $+[0]-$-[0]+1), " at offset ", $-[0];
}

是的,它也会找到非字母字符。但你能找到那个微妙的错误吗? - ysth

1

顺便说一下,除了 RegExBuddy 之外,另一个非常方便的免费正则表达式测试网站是 gskinner.com 上的 RegExr。 它可以很好地处理 ([[:alpha:]])(\1+)


0

这样怎么样:

(\w)\1+

第一部分围绕一个字符创建了一个未命名的组,然后反向引用查找相同的字符。


这只匹配前两个重复的字符,而不是整个重复子串。 - Michael Carman

0

我认为这个也可以工作:

((\w)(?=\2))+\2


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接