12

I want to find 10 digit numbers with no repeat digits, for example:

1123456789 //fail, there are two 1's
6758951230 //fail, there are two 5's
6789012345 //pass, each digit occurs once only. 

at the moment I am using regex but can only match 10digits numbers(it doesnt check for duplicates. I am using this regex:

[0-9]{10}

Can this be done with regex or is there a better way to achieve this?

Sionnach733
  • 4,686
  • 4
  • 36
  • 51
  • you'll have to use backreferences to check if a number was not already captured. – njzk2 Nov 25 '13 at 23:32
  • 9
    This is not a problem suitable for regexes. Just write a simple loop and use a boolean[10] array to record the occurrence of each digit. – Jim Garrison Nov 25 '13 at 23:32
  • @JimGarrison It absolutely *is* a job for regex: see [my answer](http://stackoverflow.com/questions/20205653/regex-to-find-numbers-with-unique-digits/20206052#20206052) for how to do it. Never say never :) – Bohemian Nov 26 '13 at 00:09
  • For a unique 10 digit number within a > 10 digit string, I don't see the solution using a regex unless its a boolean type assertion (like I posted). Maybe its possible, but probably not using `*` quantifiers. –  Nov 26 '13 at 17:07

5 Answers5

11

This regex works:

^(?!.*(.).*\1)\d{10}$

This uses an anchored negative look ahead with a back reference to assert that there are no repeating characters.

See a live demo working with your examples.

In java:

if (str.matches("^(?!.*(.).*\\1)\\d{10}"))
    // number passes
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • Can you get this to work for a floating (substring) 10 digit number? Will it work without the anchors? –  Nov 26 '13 at 01:46
  • @sin sure, but can you give an example of what you mean? Eg `12345.06789` or `1234.0123456789` or something else? – Bohemian Nov 26 '13 at 02:53
  • `112346578910100010` Just a trivial example. Because your regex uses the many quantifiers, without the anchors it will always blow past a 10 digit boundry. Unless you can think of another way, but I think a boolean type of regex like I posted is the only way. –  Nov 26 '13 at 16:57
  • @sln my answer works correctly: it will not match `1111234567890000`. Read my answer carefully: `String.matches()` must match the .*whole* string to return true, so ^ and $ are implied (added automatically to the front and back of the regex). Ie `str.matches("foo")` is identical to `String.matches("^foo$")`, so anchors are not required. – Bohemian Nov 26 '13 at 19:07
  • Yeah, don't know Java but your right most "Match" functions imply the whole string. I was talking about Search as in substring. I'm sure Java has that. Will your regex ever work in that context? Or even in for example `^.*.*$` for "Match". –  Nov 26 '13 at 20:04
  • @sln i don't know what you mean, but I will say that afaik there is no regex-based substring method. You can extract a substring by using `replaceAll()` with a capturing regex and a back reference in the replacement string. – Bohemian Nov 26 '13 at 23:23
  • There a matcher() function. Why wouldn't that work to find a substring. Could your regex be modified to find a unique 10 digit substring using `pattern.matcher`? .. Pattern pattern = Pattern.compile(pattern_string); Matcher matcher = pattern.`matcher`(sample); if (matcher.find() .. –  Nov 27 '13 at 01:29
  • @sln it could be done, but the regex would be enormous because a look ahead can not be limited in length, so every combination of lengths around the capture, and every length from 2 to 10, would have to be coded as separate look aheads (I think it's 45 in all). – Bohemian Nov 27 '13 at 12:55
  • I'm lost, so.. could you post that in an edit? So I could see it. –  Nov 27 '13 at 21:50
  • @sln I am not going to post it. It's not a good idea. It can be done, but it would be "bad" code. You would do it another way, probably applying the regex in the answer to subsequent 10-char chunks got from a loop – Bohemian Nov 27 '13 at 23:36
  • @Bohemian Could someone explain the regex `^(?!.*(.).*\1)\d{10}$` ? – Huei Tan Jun 29 '15 at 16:26
  • 1
    @Huei see the "Explanation" section of [this page](https://regex101.com/r/tL0vL4/1) – Bohemian Jun 29 '15 at 17:20
  • `.*` causes a lot of **redundant backtracking** - instead we can switch to a lazy backtracking using a `?`, see my answer below. – Om Shankar Oct 15 '15 at 22:17
  • @OmShankar sure, you can make it more efficient, but that's an optimization and a little harder to read. Regex is hard enough to read anyway, and for "sentence sized" input will return in micro seconds, which is good enough. – Bohemian Oct 16 '15 at 01:38
  • I feel `!/(.).*?\1/` is still easier to read than `^(?!.*(.).*\1)\d{10}$` - and lesser to explain too. Even the link you gave, explains my regex to be better: _between zero and unlimited times, **as few times as possible, expanding as needed [lazy]**_ – Om Shankar Oct 19 '15 at 07:29
1

Try this one (?:([0-9])(?!.*\1)){10}, this will work if you're validating numbers one at a time.

This should work (?:([0-9])(?!\d*\1)){10} to search for each occurance of an unique 10-digit sequence, but it will fail with 12345678901234567890, will find the last valid part 1234567890 instead of ignoring it.

Source and explanations: https://stackoverflow.com/a/12870549/1366360

Community
  • 1
  • 1
mdolbin
  • 936
  • 4
  • 8
  • @OGHaza give me the number you've tested, please – mdolbin Nov 25 '13 at 23:45
  • Tested this at http://www.regexplanet.com/advanced/java/index.html, worked for both cases presented by the OP – Wusiji Nov 25 '13 at 23:45
  • For example [1111111111](http://regexr.com?37c3m), but on closer inspection, this may well almost work (it looks for non-repeating sets of 10 digits, i.e. where the next 10 digits can't be the same as the first 10). – OGHaza Nov 25 '13 at 23:46
  • Thats because they have to be in sets of 10. 9 digits will always fail, 11 digits will always fail. – OGHaza Nov 25 '13 at 23:49
  • @OGHaza ok, the reason is this `{10}` I've added, it turns out that I allowed each character to continiously repeat up to 10 times. Try `^(?:([0-9])(?!.*\1))*$` But we still need to set 10 character length somehow, give me a while. – mdolbin Nov 25 '13 at 23:50
1

Here's the shortest and efficient regex with less backtracking due to the presence of a ?.

Works for any length of input:

!/(.).*?\1/.test(number)

Examples:

!/(.).*?\1/.test(1234567890) // true
!/(.).*?\1/.test(1234567490) // false - note that it also works for repeated chars which are not adjacent.

Demo
- checks for repeated digits
- opposite of what you want, because rubular doesn't allow a !

Om Shankar
  • 7,989
  • 4
  • 34
  • 54
0

lancemanfv regex reference https://stackoverflow.com/a/12870549/1366360 is a great one, but the suggested regex is slightly off.

Instead try

^(?:([0-9])(?!.*\1)){10}$ 

This will match any string that begins and ends with 10 digits that are all different.

If you want to check (and extract) if a longer string contains a 10 digit number with each number different use this

((?:([0-9])(?!.*\2)){10})*

You can then use a numbered reference to extract the matching number

Community
  • 1
  • 1
bdrx
  • 924
  • 13
  • 31
  • The anchored regex works for just a 10 digit string, but the second regex will likely never work because it uses the many quantifier `.*` which will always blow past a 10 digit boundry. –  Nov 26 '13 at 17:02
0

Works every time (I see this question) -

Revised to define Grp 10 before the (?! \10 ) assertion. \1-\9 are always considered backrefs (> \10, the parenth's must be before it is referenced).
So made them all the same as well.

Note- this can be used to find a floating (substring) 10 uinque digit number. Requires no anchors.
Fyi - With Perl, the \g{#} (or \k'name') syntax could be used before the group is defined, no matter what number the group number is.

 #  "(?:((?!\\1)1)|((?!\\2)2)|((?!\\3)3)|((?!\\4)4)|((?!\\5)5)|((?!\\6)6)|((?!\\7)7)|((?!\\8)8)|((?!\\9)9)|((?!\\10)0)){10}"


 (?:
      (                      # (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
      )
   |  (                      # (10)
           (?! \10 )
           0
      )
 ){10}