1

I'm quite new to regex, and not sure what I'm doing wrong exactly.

I'm looking for a regex that match the following number format:

Matching requirements:

  1. Must start with either 0 or 3
  2. Must be between 7 to 11 digits
  3. Must not allow ascending digits. e.g. 0123456789, 01234567
  4. Must not allow repeated digits. e.g. 011111111, 3333333333, 0000000000

This is what I came up with:

^(?=(^[0,3]{1}))(?!.*(\d)\1{3,})(?!^(?:0(?=1|$))?(?:1(?=2|$))?(?:2(?=3|$))?(?:3(?=4|$))?(?:4(?=5|$))?(?:5(?=6|$))?(?:6(?=7|$))?(?:7(?=8|$))?(?:8(?=9|$))?9?$).{7,11}$

The above regex fails the No. (4) condition. Not sure why though.

Any help would be appreciated.

Thanks

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
JOJO
  • 13
  • 3

2 Answers2

0

A solution for a JS flavor of PCRE would be

/^[03](?!123456(7(8(9|$)|$)|$))(?!(?<d>.)\k<d>+$)[0-9]{6,10}$/

Explanations

  1. ^[03] starts at the beginning of the string, then reads either 0 or 3
  2. (?!123456(7(8(9|$)|$)|$)) makes sure that, after this first char, there is no sequence (if a sequence can be read, then the negative lookahead fails
  3. (?!(?<d>.)\k<d>+$) is another negative lookahead : it ensures that the first char read (flagged d) is not repeated again and again until end of string
  4. [0-9]{6,10}$/ finally reads 6 to 10 digits (first one already read)

A few tests:

  • "0123456789: No match"
  • "01234567: No match"
  • "01234568: No match"
  • "011111111: No match"
  • "33333333: No match"
  • "333333233 is valid"
  • "042157891023 is valid"
  • "019856: No match"
  • "0123451245 is valid"
David Amar
  • 247
  • 1
  • 5
0

A few notes about the pattern that you tried

  • You can omit the {1} and the comma in [0,3]
  • In the lookahead (?!.*(\d)\1{3,}) the (\d) is the second capturing group because this (?=(^[0,3]{1})) contains the first capturing group so it should be \2 instead of \1
  • In the lookahead, you can omit the comma in {3,}
  • In the match itself you use .{7,11} where the dot would match any character except a newline. You could use \d instead to match only digits

You pattern might look like

^(?=(^[03]))(?!.*(\d)\2{3})(?!^(?:0(?=1|$))?(?:1(?=2|$))?(?:2(?=3|$))?(?:3(?=4|$))?(?:4(?=5|$))?(?:5(?=6|$))?(?:6(?=7|$))?(?:7(?=8|$))?(?:8(?=9|$))?9?$)\d{7,11}$

Regex demo

Or leaving out the first lookahead and move that to the match, changing the quantifier to \d{6,10} and repeating capture group \1 instead of \2

^(?!.*(\d)\1{3})(?!(?:0(?=1|$))?(?:1(?=2|$))?(?:2(?=3|$))?(?:3(?=4|$))?(?:4(?=5|$))?(?:5(?=6|$))?(?:6(?=7|$))?(?:7(?=8|$))?(?:8(?=9|$))?9?$)[03]\d{6,10}$

Regex demo

Edit

Based on the comments, the string not having 4 ascending digits:

^(?!.*(\d)\1{3})[03](?!\d*(?:0123|1234|2345|3456|4567|5678|6789))\d{6,10}$

Regex demo

The fourth bird
  • 154,723
  • 16
  • 55
  • 70