Minh Nguyễn
Minh Nguyễn

Reputation: 33

Regular Expressions: Positive and Negative Lookahead Solution

I was doing Freecodecamp RegEx challange, which's about:

Use lookaheads in the pwRegex to match passwords that are greater than 5 characters long, do not begin with numbers, and have two consecutive digits

So far the solution I found passed all the tests was:

/^[a-z](?=\w{5,})(?=.*\d{2}\.)/i

However, when I tried

/^[a-z](?=\w{5,})(?=\D*\d{2,}\D*)/i

I failed the test trying to match astr1on11aut (but passed with astr11on1aut). So can someone help me explaining how ?=\D*\d{2,}\D* failed this test?

Upvotes: 3

Views: 1246

Answers (3)

Aobo Cheng
Aobo Cheng

Reputation: 4548

Failed for the \d{2,}

Then let's have a look at the regexp match process

/^[a-z](?=\w{5,})

means start with [a-z], the length is at least 6, no problem.

(?=\D*\d{2,}\D*)

means the first letter should be followed by these parts:

[0 or more no-digit][2 or more digits][0 or more no-digits]

and lets have a look at the test case

astr1on11aut
// ^[a-z] match "a"
// length matchs
// [0 or more no-digit]: "str"
// d{2,} failed: only 1 digit

the ?= position lookahead means exact followed by.


The first regular expression is wrong, it should be

/^[a-z](?=\w{5,})(?=.*\d{2}.*)/i

Upvotes: 3

The fourth bird
The fourth bird

Reputation: 163632

So can someone help me explaining how (?=\D*\d{2,}\D*) failed this test?

Using \D matches any char except a digit, so from the start of the string you can not pass single digit to get to the 2 digits.

Explanation

astr1on11aut                            astr11on1aut
    ^                                       ^^
    Can not pass 1 before reaching 11       Can match 2 digits first

Note

  • the expression could be shortened to (?=\D*\d{2}) as it does not matter if there are 2, 3 or more because 2 is the minimum and the \D* after is is optional.

  • the first expression ^[a-z](?=\w{5,})(?=.*\d{2}\.) can not match the example data because it expects to match a . literally after 2 digits.

Upvotes: 3

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 627537

When it comes to lookahead usage in regex, rememeber to anchor them all at the start of the pattern. See Lookarounds (Usually) Want to be Anchored. This will help you avoid a lot of issues when dealing with password regexps.

Now, let's see what requirements you have:

  • "are greater than 5 characters long" => (?=.{6}) (it requires any 6 chars other than lien break chars immediately to the right of the current location)
  • "do not begin with numbers" => (?!\d) (no digit allowed immediately to the right)
  • have two consecutive digits => (?=.*\d{2}) (any two digit chunk of text is required after any 0 or more chars other than line break chars as many as possible, immediately to the right of the current location).

So, what you may use is

^(?!\d)(?=.{6})(?=.*\d{2})

Note the most expensive part is placed at the end of the pattern so that it could fail quicker if the input is non-matching.

See the regex demo.

Upvotes: 2

Related Questions