2

To some extent I understand positive lookahead.

X(?=Y), it means "look for X, but match only if followed by Y"

But in the below regex - I don't understand the significance of positive lookahead at the beginning of regex.

^(?:(?=.*\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))(?!.*(.)\1{2,})

Can some one explain what the positive lookahead is doing at the beginning and what the above regex does.

Edit - Here is the entire regex if it helps -

^(?:(?=.*\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[^A-Za-z0-9])(?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))(?!.*(.)\1{2,})[A-Za-z0-9]{8,64}$

The regex on a whole is supposed to match a string with characters containing both uppercase, lowercase, numeric and be 8 to 64 chars long.

2
  • Can you provide some more context on what you think the regexp is supposed to do, or what it is advertised to do? Oct 11, 2021 at 17:45
  • @GerardvanHelden - i edited the Q. Please see if you can help
    – samshers
    Oct 11, 2021 at 17:55

1 Answer 1

3

Your ^(?:(?=.*\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))(?!.*(.)\1{2,}) regex is equal to

^(?=.*\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9])(?!.*(.)\1{2,})`

See the regex demo.

Lookaheads here require specific patterns to be present (?=) or absent (?!) after any zero or more characters other than line break characters. This is a typical password checking regex.

They are used after ^ anchor, start of string, as it is enough to run each lookahead check just once at the start of the string. Since lookarounds are zero-width assertions, all four lookaheads are triggered one by one at the start of string.

It matches

  • ^ - start of string
  • (?=.*\d) - there must be at least one digit after any zero or more chars other than line break chars
  • (?=.*[A-Z]) - there must be at least one uppercase ASCII letter after any zero or more chars other than line break chars
  • (?=.*[^A-Za-z0-9]) - there must be at least one char other than ASCII alphanumeric char after any zero or more chars other than line break chars
  • (?!.*(.)\1{2,}) - there should be no 3 or more identical consecutive chars other than line break chars after any zero or more chars other than line break chars.

Sometimes, regex functions require a full string match, so .* might be required at the end of this pattern.

Your second regex is actually equal to ^(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?!.*(.)\1{2,})[A-Za-z0-9]{8,64}$. Here is this regex demo with explanation. All alternatives with (?=.*[^A-Za-z0-9]) will never match because the consuming pattern part - [A-Za-z0-9]{8,64} - only matches ASCII letters or digits, and will never match any chars other than ASCII alphanumeric chars.

9
  • if i have to remove "should not be no 3 or more identical consecutive chars" condition. what would the sub-regex look like or the whole regex look like
    – samshers
    Oct 11, 2021 at 18:00
  • @samshers Just remove (?!.*(.)\1{2,}) and the condition will be "subtracted". Oct 11, 2021 at 18:01
  • so here positive lookahead is used to only validate a condition but not include it in match. Like search --> match --> then discard the searched char(s).
    – samshers
    Oct 11, 2021 at 18:05
  • @samshers Lookaheads are zero-width assertions The texts they match do not get added to the overall match value, the result of each lookahead is either true (then it means "go ahead matching") or false (stop matching this way, backtrack, or, if backtracking is not possible, fail the match). Oct 11, 2021 at 18:12
  • 1
    @samshers Matching is finding text that matches a pattern, and it is done by all the regex parts. [A-Za-z0-9]{8,64} is a consuming pattern part, i.e. the part of the pattern that makes the regex index advance through the string from left to right, and append the matched text to the whole match value. Oct 11, 2021 at 18:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .