Regex satisfying several conditions

Viewed 64

Using python, I am trying to identify strings that verify the following conditions:

  1. It must contain 9 characters
  2. Characters 2 to 8 must be numbers
  3. Characters 1 and 9 can be numbers or letters (lower or upper)
  4. Characters 1 and 9 can't be both numbers.

For example, 'A12345678', '01234567A' and 'A1234567B' will match, but '012345678' will not match.

For conditions 1 to 3 I use '([a-z]|[A-Z]|[0-9])[0-9]{7}([a-z]|[A-Z]|[0-9])$'. For condition 4 I use '(?![0-9]{9}$)'. However, I don't know how to join those conditions in a unique regex. Can somebody help me? Thanks in advance!

4 Answers

Separate the two cases (letter in the front/letter in the back)

^([A-Z][0-9]{7}[A-Z0-9]|[A-Z0-9][0-9]{7}[A-Z])$

Apply with the "case insensitive" flag.

Alternatively, you could try:

^(?=\D?\d{7,8}\D?$)[A-Z\d]{9}

See the online demo

  • ^ - Start string anchor.
  • (?= - Open a positive lookahead.
    • D? - Optional non-digit.
    • \d{7,8} - 7 Or 8 digits.
    • D? - Optional non-digit.
    • $) - End string anchor and close positive lookahead.
  • [A-Z\d]{9} - 9 Characters from the given class.

Or, assuming single string validation, you could try:

^(?!\d{9}|.*_|.+\D.)\w{9}$
  • ^ - Start string anchor.
  • (?! - Open negative lookahead:
    • \d{9} - Nine digits.
    • | - Or:
    • .*_ - Any underscore anywhere in the string.
    • | - Or:
    • .+\D. - Any 1+ char followed by non-digit and another char.
    • ) - Close negative lookahead.
  • \w{9} - Nine word-characters.
  • $ - End string anchor.

This

 r"^((?:[0-9]{8})(?:[a-z]|[A-Z])|(?:[a-z]|[A-Z])(?:[0-9]{8})|(?:[a-z]|[A-Z])[0-9]{7}(?:[a-z]|[A-Z]))$"

 # or with ignore case
 r"^([0-9]{8}[a-z]|[a-z][0-9]{8}|[a-z][0-9]{7}[a-z])$"

would match

(?:[0-9]{8})(?:[a-z]|[A-Z])             # 8 numbers + letter
(?:[a-z]|[A-Z])(?:[0-9]{8})             # letter + 8 numbers
(?:[a-z]|[A-Z])[0-9]{7}(?:[a-z]|[A-Z])  # letter + 7 numbers + letter

You can reduce it with the re.I flag for case insensitivity.

I replaced the capturing groups with non-grouping groups.

Demo: https://regex101.com/r/Nr5wus/3 and https://regex101.com/r/bypoGq/2 (ignore case)

You can use a conditional in the regex pattern:

^(?:([A-Z])|[0-9])[0-9]{7}(?(1)[A-Z0-9]|[A-Z])$

See the regex demo.

Details:

  • ^ - start of string
  • (?:([A-Z])|[0-9]) - either a letter (captured in Group 1) or a digit
  • [0-9]{7} - seven digits
  • (?(1)[A-Z0-9]|[A-Z]) - if Group 1 matched, match a letter or digit, else, only match a letter
  • $ - end of string.
Related