be a nice trick, it’s not required. Lookaheads are necessary whenever there is overlap‐
ping content, and they can simplify certain types of matching.
A classic example is validating that a password matches some policy. To keep it sim‐
ple, let’s say our password must contain at least one uppercase letter, number, and
lowercase letter, and no nonletter, nonnumber characters. We could, of course, use
multiple regexes:
function
validPassword
(
p
) {
return
/[A-Z]/
.
test
(
p
)
&&
// at least one uppercase letter
/[0-9]/
.
test
(
p
)
&&
// at least one number
/[a-z]/
.
test
(
p
)
&&
// at least one lowercase letters
!
/[^a-zA-Z0-9]/
.
test
(
p
);
// only letters and numbers
}
Let’s say we want to combine that into one regular expression. Our first attempt fails:
function
validPassword
(
p
) {
return
/[A-Z].*[0-9][a-z]/
.
test
(
p
);
}
Not only does this require the capital letter to come before the numbers to come
before the two lowercase letters, but we haven’t tested for the invalid characters at all.
And there’s really no sensible way to do it, either, because characters are consumed as
the regex is processed.
Lookaheads come to the rescue by not consuming input; essentially each lookahead is
an independent regex that doesn’t consume any input. Lookaheads in JavaScript look
like
(?=<subexpression>)
. They also have a “negative lookahead”:
(?!<subexpres
sion>)
will match only things that aren’t followed by the subexpression. Now we can
write a single regex to validate our passwords:
function
validPassword
(
p
) {
return
/(?=.*[A-Z])(?=.*[0-9])(?=.*[a-z])(?!.*[^a-zA-Z0-9])/
.
test
(
p
);
}
You might be looking at this soup of letters and characters and thinking that our
multiregex function is better—or at least easier to read. And in this example, I would
probably agree. However, it demonstrates one of the important uses of lookaheads
(and negative lookaheads). Lookaheads definitely fall into the category of “advanced
regex,” but are important for solving certain problems.
Constructing Regexes Dynamically
We started off this chapter by saying that you should prefer the regex literal over the
RegExp
constructor. In addition to having to type four fewer letters, we prefer the
regex literal because we don’t have to escape backslashes as we do in JavaScript
strings. Where we do need to use the
RegExp
constructor is when we want to con‐
struct regexes dynamically. For example, you might have an array of usernames you
Constructing Regexes Dynamically | 255