views:

1909

answers:

9

I am looking for a regex that will find repeating letters. So any letter twice or more, for example:

booooooot or abbott

I won't know the letter I am looking for ahead of time.

This is a question I was asked in interviews and then asked in interviews. Not so many people get it correct.

+5  A: 

Use \N to refer to previous groups:

/(\w)\1+/g
Jonathan Lonowski
A: 

How about:

(\w)\1+

The first part makes an unnamed group around a character, then the back-reference looks for that same character.

Joseph Pecoraro
This only matches the first two repeating chars, not the whole repeating substring.
Michael Carman
HAHAHA! nice edit! gave you a +1 just cuz your funny. and I too fight the neg-bombs. ;0)
Keng
+8  A: 

I Think using a backreference would work:

(\w)\1+

\w is basically [a-zA-Z_0-9] so if you only want to match letters between A and Z (case insensitively), use [a-zA-Z] instead.

(EDIT: or, like Tanktalus mentioned in his comment (and as others have answered as well), [[:alpha:]], which is locale-sensitive)

hasseg
instead of [a-zA-Z], just use [[:alpha:]] which is locale-sensitive ;-)
Tanktalus
+32  A: 

You can find any letter, then use \1 to find that same letter a second time (or more). If you only need to know the letter, then $1 will contain it. Otherwise you can concatenate the second match onto the first.

my $str = "Foooooobar";

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

print $1;
# prints 'o'
print $1 . $2;
# prints 'oooooo'
Adam Bellaire
For just letters swap out \w for [a-zA-Z].
TomC
@TomC: That's not unicode safe!
Leon Timmermans
Now I can replace doubled letters for just one: Regex.Replace(str, @"(\w)\1+", "$1"); thank you Adam.
Junior Mayhé
+11  A: 

I think you actually want this rather than the "\w" as that includes numbers and the underscore.

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

Ok, ok, I can take a hint Leon. Use this for the unicode-world or for posix stuff.

([[:alpha:]])\1+
Keng
We live in a unicode world. [a-zA-Z] will not cover most languages. [[:alpha:]] would be more correct.
Leon Timmermans
oh you crazy foreigners! ;o)yeah, posix would be a better syntax for the non-American English chars.
Keng
+3  A: 

You might want to take care as to what is considered to be a letter, and this depends on your locale. Using ISO Latin-1 will allow accented Western language characters to be matched as letters. In the following program, the default locale doesn't recognise é, and thus créé fails to match. Uncomment the locale setting code, and then it begins to match.

Also note that \w includes digits and the underscore character along with all the letters. To get just the letters, you need to take the complement of the non-alphanum, digits and underscore characters. This leaves only letters.

That might be easier to understand by framing it as the question "What regular expression matches any digit except 3?", and the answer is /[^\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
dland
+2  A: 

The Following code will return all the characters, which ever repeating twice or more.

my $str = "SSSannnkaaarsss";

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

+1  A: 

FYI, aside from RegExBuddy, a real handy free site for testing regular expressions is RegExr at gskinner.com. Handles ([[:alpha:]])(\1+) nicely.

bill weaver
+1  A: 

Just for kicks, a completely different approach:

if ( ($str ^ substr($str,1) ) =~ /\0+/ ) {
    print "found ", substr($str, $-[0], $+[0]-$-[0]+1), " at offset ", $-[0];
}
ysth
Yes, it will find non-letters too. But can you find the subtle bug?
ysth