7

I have a regular expression of the following:

.regex(/^(?!^[0-9]*$)(?!^[a-zA-Z]*$)^([a-zA-Z0-9]{4})$/)

Must be exactly 4 characters Must contain at least 1 numeric and 1 alpha

Although I rarely do regular expression, this was relatively easy. I now have a new requirement that I have tried to implement, but cannot get right.

New requirement: Be able to have a comma separated list of the same type of input as before. Cannot end with a comma. Each item must be valid per the rules above (4 characters, at least on numeric, at least one alpha)

Valid:  123F,U6Y7,OOO8
Invalid:  Q2R4,
Invalid:  Q2R4,1234
Invalid:  Q2R4,ABCD
Invalid:  Q2R4,N6

I very much appreciate your help! Thanks!

PakkuDon
  • 1,627
  • 4
  • 22
  • 21
user3006614
  • 127
  • 1
  • 2

4 Answers4

10

Some of the other answers are repeating the lookahead assertions. That's not necessary.

Here's a regular expression that matches a comma-separated sequence of atoms, where each atom is four alphanumeric characters:

^[A-Z0-9]{4}(?:,[A-Z0-9]{4})*$

Of course, that's not quite what you want. You don't want atoms that are all alphabetic. Here's a negative lookahead assertion that prevents matching such an atom anywhere in the text:

(?!.*[A-Z]{4})

And you don't want atoms that are all numeric either:

(?!.*[0-9]{4})

Putting it all together:

^(?!.*[A-Z]{4})(?!.*[0-9]{4})[A-Z0-9]{4}(?:,[A-Z0-9]{4})*$
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
3

This regex should work:

^(?:(?![0-9]*,)(?![a-zA-Z]*,)[a-zA-Z0-9]{4},)*(?![0-9]*$)(?![a-zA-Z]*$)[a-zA-Z0-9]{4}$

Or you can shorten [0-9] to \d. It doesn't really matter, though, since the expanded code can be more readable.

^(?:(?!\d*,)(?![a-zA-Z]*,)[a-zA-Z\d]{4},)*(?!\d*$)(?![a-zA-Z]*$)[a-zA-Z\d]{4}$

You can see how your regex is transformed to make this regex, when I line it up like below:

^
(?:
  (?!\d*,)(?![a-zA-Z]*,)[a-zA-Z\d]{4},
)*
  (?!\d*$)(?![a-zA-Z]*$)[a-zA-Z\d]{4}
$
nhahtdh
  • 55,989
  • 15
  • 126
  • 162
2

Try using this regex (regex test):

.regex(/^(?:(?![0-9]{4}|[a-zA-Z]{4})[a-zA-Z0-9]{4})(?:(?:\b\,)(?![0-9]{4}|[a-zA-Z]{4})[a-zA-Z0-9]{4})*$/)

Explanation:

  • (?:\b\,) -> Match with a , at the beginning of the string only if its preceded by a word boundary

  • (?:(?![0-9]{4}|[a-zA-Z]{4})[a-zA-Z0-9]{4}) -> Match a string with letter and digits only if dont have 4 digits ow 4 letters

Caio Oliveira
  • 1,243
  • 13
  • 22
1

I want to highlight the advantage of my answer as comparison to other answers as follows:

  • My answer intuitively encodes the requirement "at least one alpha" and "at least one numeric".
    Other answers make use of the fact that considering the universal set of [a-zA-Z0-9], which after some thoughts, those two requirements translate into "not all alpha and not all digits".
  • In my answer, you can change the universal set to anything you want (even with a comma!), and don't need to change the regex for the other requirements.

My answer:

^(?=.{0,3}\d)(?=.{0,3}[a-zA-Z])[a-zA-Z0-9]{4}(,(?=.{0,3}\d)(?=.{0,3}[a-zA-Z])[a-zA-Z0-9]{4})*$

Regular expression visualization

Debuggex Demo

Explained as:

^
  (?=.{0,3}\d)(?=.{0,3}[a-zA-Z])[a-zA-Z0-9]{4}   # Main part
  (,
    (?=.{0,3}\d)(?=.{0,3}[a-zA-Z])[a-zA-Z0-9]{4}
  )*
$

The "main part" matches any four characters composed by alphanumerics ([a-zA-Z0-9]{4}), containing at least one digit ((?=.{0,3}\d)) and at least one letter ((?=.{0,3}[a-zA-Z])). Then just repeat that pattern preceded with a comma.

justhalf
  • 8,960
  • 3
  • 47
  • 74