3

Sorry if this is answered somewhere, but I couldn't find it.

I need to write a regexp to matches on strings that contain the digits from 0 to 9 exactly once. For example:

e8v5i0l9ny3hw1f24z7q6

You can see that numbers [0-9] are present exactly once and in random order. (Letters are present also exactly once, but that is an advanced quest...) It must not match if a digit is missing or if any digit is present more than one time.

So what would be the best regexp to match on strings like these? I am still learning regex and couldn't find a solution. It is PCRE, running in perl environment, but I cannot use perl, only the regex part of it. Sorry for my english and thank you in advance.

ULLAS MOHAN.V
  • 1,546
  • 1
  • 18
  • 36
Tom
  • 89
  • 1
  • 6

3 Answers3

6

What about this pattern to verify the string:

^\D*(?>(\d)(?!.*\1)\D*){10}$
  • ^\D* Starts with any amount of characters, that are no digit
  • (?>(\d)(?!.*\1)\D*){10} followed by 10x: a digit (captured in first capturing group), if the captured digit is not ahead, followed by any amount of \D non-digits, using a negative lookahead. So 10x a digit, with itself not ahead consecutive should result in 10 different [0-9].

\d is a shorthand for [0-9], \D is the negation [^0-9]

Test at regex101, Regex FAQ


If you need the digit-string then, just extract the digits, e.g. php (test eval.in)

$str = "e8v5i0l9ny3hw1f24z7q6";

$pattern = '/^\D*(?>(\d)(?!.*\1)\D*){10}$/';

if(preg_match($pattern, $str)) {
  echo preg_replace('/\D+/', "", $str);
}
Community
  • 1
  • 1
Jonny 5
  • 11,051
  • 2
  • 20
  • 42
  • 1
    This seems to work as I think it should work! At least at debuggex.com says so. :) Thank you! – Tom Apr 14 '14 at 11:22
0

It is easy to create a regular expression that matches one specific permutations of the numbers and ingnore the other characters. E.g.

^[^\d]*0[^\d]1[^\d]*2[^\d]*3[^\d]*4[^\d]*5[^\d]*6[^\d]*7[^\d]*8[^\d]*9[^\d]*$

You can combine 10! expressions for every possible permutation with |

Although this is completely inpractical it shows that such a regular expression (without lookahead) is indeed possible.

However this is something that is much better done without regular expression matching.

Udo Klein
  • 6,381
  • 1
  • 31
  • 53
0
$s = "e8v5i0l9ny3hw1f24z7q6";
$s = preg_replace('/[^\d]/i', '', $s); //remove non digits
if(strlen($s) == 10) //do we have 10 digits ?
if (!preg_match('/(\d)(\1+)/i', $s))  //if no repeated digits
echo "String has 10 different digits";

http://ideone.com/eY4eGx

Pedro Lobito
  • 75,541
  • 25
  • 200
  • 222