Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pandigital Regex?

Tags:

regex

What's a regular expression that validates if a string is pandigital (containing all digits from 1 to 9 exactly once)?

For example:

123456789
891364572

But not:

11234556789
25896471

I know how to do this without regex but I was unable to form a regex for it.

Thanks.

This is not homework.

like image 244
Bai Li Avatar asked Apr 17 '09 01:04

Bai Li


People also ask

How do you check if a number is pandigital?

A Pandigital number is an integer that has each digit of its base at least once.

How do I get a Pandigital number?

A pandigital number is a number that contains each digit starting from one, up to the total length of the number. For instance, 15342 is a pandigital number, since it has all the digits starting from zero up to the total length of the number, which is 5.


2 Answers

Short and sweet, using a negative lookahead:

/^(?!.*([1-9]).*\1)[1-9]{9}$/
  • [1-9] is the character class for nonzero digits - equivalent to [123456789]
  • .* matches any string of any length.
  • .*([1-9]).*\1.* matches any string with that contains at least two occurrences of the same nonzero digit
    • a nonzero digit is matched and captured by ([1-9])
    • a repeat of that nonzero digit is matched by \1, a back-reference to the first captured match.
    • the .* matches the arbitrary padding before, and between the nonzero digit and its repeat.
  • (?!<pattern>) matches any position where the contained pattern doesn't match. This is a negative lookahead, as it only matches a position in the string, and doesn't consume any of it - just looks ahead to compare it with the contained pattern.
  • [1-9]{9} matches nine nonzeo digits.
    • <pattern>{9} means match the preceding pattern 9 times.
  • ^<pattern>$ matches any string that exactly matches the contained pattern (rather than contains a substring that matches the pattern)
    • ^ matches the position at the beginning of a string OR the beginning of a line
    • $ matches the position at the end of a string OR the end of a line

So combined, we check to make sure that it's not repeating any digits, then we check that it's only digits. Since it's 9 digits long, and none repeat, all must show up exactly once. That's the pigeonhole principle at work!

The syntax for your specific regular expression engine may vary. The above is a PCRE (supported in Perl, Ruby, and a bunch of different other languages). Posix regular expressions have slightly different syntax. Not all engines support negative lookaheads, but most support back-references. Neither are part of the definition of formal theoretic regular expressions, but are very convenient.

like image 97
rampion Avatar answered Oct 31 '22 02:10

rampion


Regex is not exactly the best tool for the job here, but here you go:

^(?=[^1]*1[^1]*$)(?=[^2]*2[^2]*$)(?=[^3]*3[^3]*$)(?=[^4]*4[^4]*$)(?=[^5]*5[^5]*$)(?=[^6]*6[^6]*$)(?=[^7]*7[^7]*$)(?=[^8]*8[^8]*$)(?=[^9]*9[^9]*$)[1-9]+$

(?= ) is a look-ahead. It does not actually fit the description of regular expressions, as it does not describe a regular language.

like image 45
Markus Jarderot Avatar answered Oct 31 '22 00:10

Markus Jarderot