How to use regular expressions to match numbers with some exceptions

0 votes
asked Sep 11, 2017 by sgtpepper

I need to match numbers in groups of 5, from 1 to 5, with the following exceptions:

  1. Numbers can't include zeros
  2. Numbers can't be like 11111, 22222 and so on.
  3. Numbers can't be like 12345 or 54321

Some examples of valid numbers:

14252, 45121, 43412, 51321 ...

So far I got an expression to group the numbers and do not allow zeros.

/[1-5]{5}/ 

But I'm having some trouble to handle the second and third exceptions. I tried unsuccessfully to use a negative lookahead to disallow a match if I have a pattern of repeated numbers.

?!11111|?!22222 

I'm trying with this expression:

((?!11111)[1-5]{5}?)

How can I write regular expressions to not match certain patterns?

I will eventually change it to not match any other sequence of numbers.

4 Answers

0 votes
answered Sep 11, 2017 by dan-kreiger

How about this?

^(?!([1-5])\1{4})(?!54321)(?!12345)[1-5]{5}$
0 votes
answered Sep 11, 2017 by zambonee

You have the right idea using negative lookaheads, just the syntax was a little off. This works for me:

\A(?!11111|22222|33333|44444|55555|12345|54321)[1-5]{5}\z

0 votes
answered Sep 11, 2017 by schwern

First off, you don't have to cram everything into one regex. Regexes are already complicated, if you can do it in multiple regexes, that will often make things much simpler and allow for more flexible code. For example, you can customize the error message based on which condition failed. Usually you only need to fold multiple regexes together for performance reasons, and there are tools to do that automatically.

So far I got an expression to group the numbers and do not allow zeros.

/[1-5]{5}/

Careful, you have to anchor at both ends that else it will accept any string that contains a run of 5 of 1-5.

/\A[1-5]{5}\z/

Numbers can't be like 11111, 22222 and so on.

Use a capture within the regex to accomplish this. Capture the first number, then see if there's four more. () to capture and \1 to refer to what was captured.

/\A([1-5])\1{4}\z/'

Numbers can't be like 12345 or 54321

/\A(?:12345|54321)\z/
0 votes
answered Sep 11, 2017 by cary-swoveland

Here's a solution that does not use a regular expression. I understand we are to determine if: a) the string contains five characters; b) each character equals '1', '2', '3', '4' or '5'; c) the string contains at least two different characters; and d) the string is neither '12345' nor '54321'. We can do that as follows.

def is_ok?(str)
  str.size == 5                              &&  # five characters
  (str.chars - ['1','2','3','4','5']).empty? &&  # only the digits '1'-'5'
  str.squeeze.size > 1                       &&  # not all the same character
  str != '12345'                             &&  # not an increasing sequence  
  str != '54321'                                 # not a decreasing sequence
end

is_ok? '12543' #=> true
is_ok? '12043' #=> false
is_ok? '12643' #=> false
is_ok? '22222' #=> false
is_ok? '12345' #=> false
is_ok? '54321' #=> false
Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...