0

This regex has to match passwords that are greater than 5 characters long, do not begin with numbers, and have two consecutive digits.

All the test cases are passing the regex test.

My regex is /(?=^[a-z]+\d{2,})(?=\w{5,})/

I have to use two positive lookaheads to solve this problem to pass the tests.

But astr1on11aut is not passing the test. Why?

Link to problem- https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/regular-expressions/positive-and-negative-lookahead

Uzma Khan
  • 139
  • 1
  • 3
  • 14
  • https://regex101.com/r/JnWV5J/1 – Andreas Nov 10 '20 at 07:16
  • 2
    It fails because "astr1on11aut" starts with letters (matching `^[a-z]+`) and then has a single digit which doesn't match your constraint `\d{2,}`. Therefore, the test for `(?=^[a-z]+\d{2,})` fails. – VLAZ Nov 10 '20 at 07:19

4 Answers4

2

Your regex fails because of the first lookahead pattern (?=^[a-z]+\d{2,}). The string "astr1on11aut" starts with lowercase letters:

astr1on11aut
^^^^

This matches ^[a-z]+. However, the next part of the pattern demands two or more digits with \d{2,}, however the string only has one at that place:

   astr1on11aut
       ^^
       ||
digit -+|
        + --- not a digit

This causes the first lookahead pattern to fail.

You can express the validation rules more cleanly with three lookaheads:

  • "greater than 5 characters long: (?=.{5,})
  • "do not begin with numbers": ^(?!\d)
  • "and have two consecutive digits": (?=.*\d{2})

If we put them all together we get /(?=.{5,})(?!^\d)(?=.*\d{2})/

const regex = /^(?=.{5,})(?!\d)(?=.*\d{2})/;

test("abc");
test("123");
test("123abc");

test("abc123");
test("astr1on11aut");

test("., ;_'@=-%");
test("., ;_'@123=-%");

function test(string) {
  console.log(`${string} : ${regex.test(string)}`);
}

Note that this regex doesn't require letters. Strictly following the requirements, the only thing explicitly asked for is digits. Since the type of any other input is not specified, it's left to be anything (using .). It's best not to make too many assumptions when writing a regular expression or you might block legitimate input.

VLAZ
  • 26,331
  • 9
  • 49
  • 67
1

If you are not limited to using a single regex, I suggest splitting this into multiple tests in your host language (e.g. JavaScript):

if (input.match(/^\D/)
    && input.match(/\d{2}/)
    && input.length >= 5) {
  // password policy fulfilled
}
knittl
  • 246,190
  • 53
  • 318
  • 364
  • Lookaheads are supported by all JS engines that I'm aware of. Look*behinds* are not supported in older ones. – VLAZ Nov 10 '20 at 07:24
  • 1
    Thanks. Let's keep the answer even simpler: not everything has to be solved as a single regex. Most of the times you have a host language, so let's leverage the power of that. – knittl Nov 10 '20 at 07:30
  • Amen to that. I feel like most of my time on the regex tag is spent trying to remind people that you don't *need* a regex for everything to do with strings. However, OP's task is specifically tied to making a regular expression here. I'd still endorse a solution that doesn't only use that because we should really be teaching people more how to use strings and rely on regex less. It's a useful tool but too often misused and misapplied by people who don't actually understand regular expressions yet decide to use them anyway. Email validations make me cry. – VLAZ Nov 10 '20 at 07:34
1

Does this work for you?

(?=^\D.{5,}$).*(?=\d{2,})

The first lookahead asserts that the string must not begin with a digit but be at least 6 chars long; the second asserts that there must be at least 2 consecutive digits.

Chris Ruehlemann
  • 20,321
  • 4
  • 12
  • 34
0

This regexp passes all the tests

/(?=\w*\d\d)(?=\w{5,})(?=^[^0-9]\w*)/

I believe you could fix yours by splitting the first group.

Kirill_S
  • 11
  • 4