Assertions
Assertions include boundaries, which indicate the beginnings and endings of lines and words, and other patterns indicating in some way that a match is possible (including look-ahead, look-behind, and conditional expressions).
Types
Boundary-type assertions
Characters | Meaning |
---|---|
^ |
Matches the beginning of input. If the multiline flag is set to true,
also matches immediately after a line break character. For example,
Note: This character has a different meaning when it appears at the start of a range. |
$ |
Matches the end of input. If the multiline flag is set to true, also
matches immediately before a line break character. For example,
|
\b |
Matches a word boundary. This is the position where a word character is not followed or preceded by another word-character, such as between a letter and a space. Note that a matched word boundary is not included in the match. In other words, the length of a matched word boundary is zero. Examples:
To match a backspace character ( |
\B |
Matches a non-word boundary. This is a position where the previous and
next character are of the same type: Either both must be words, or
both must be non-words, for example between two letters or between two
spaces. The beginning and end of a string are considered non-words.
Same as the matched word boundary, the matched non-word boundary is
also not included in the match. For example,
|
Other assertions
Note: The ?
character may also be used as a quantifier.
Characters | Meaning |
---|---|
x(?=y) |
Lookahead assertion: Matches "x" only if "x" is
followed by "y". For example, / |
x(?!y) |
Negative lookahead assertion: Matches "x" only if "x"
is not followed by "y". For example, |
(?<=y)x |
Lookbehind assertion: Matches "x" only if "x" is
preceded by "y". For example,
|
(?<!y)x |
Negative lookbehind assertion: Matches "x" only if
"x" is not preceded by "y". For example,
|
Examples
General boundary-type overview example
// Using Regex boundaries to fix buggy string.
buggyMultiline = `tey, ihe light-greon apple
tangs on ihe greon traa`;
// 1) Use ^ to fix the matching at the beginning of the string, and right after newline.
buggyMultiline = buggyMultiline.replace(/^t/gim,'h');
console.log(1, buggyMultiline); // fix 'tey', 'tangs' => 'hey', 'hangs'. Avoid 'traa'.
// 2) Use $ to fix matching at the end of the text.
buggyMultiline = buggyMultiline.replace(/aa$/gim,'ee.');
console.log(2, buggyMultiline); // fix 'traa' => 'tree'.
// 3) Use \b to match characters right on border between a word and a space.
buggyMultiline = buggyMultiline.replace(/\bi/gim,'t');
console.log(3, buggyMultiline); // fix 'ihe' but do not touch 'light'.
// 4) Use \B to match characters inside borders of an entity.
fixedMultiline = buggyMultiline.replace(/\Bo/gim,'e');
console.log(4, fixedMultiline); // fix 'greon' but do not touch 'on'.
Matching the beginning of input using a ^ control character
Use ^
for matching at the beginning of input. In this example, we can get the fruits that start with 'A' by a /^A/
regex. For selecting appropriate fruits we can use the filter method with an arrow function.
let fruits = ["Apple", "Watermelon", "Orange", "Avocado", "Strawberry"];
// Select fruits started with 'A' by /^A/ Regex.
// Here '^' control symbol used only in one role: Matching beginning of an input.
let fruitsStartsWithA = fruits.filter(fruit => /^A/.test(fruit));
console.log(fruitsStartsWithA); // [ 'Apple', 'Avocado' ]
In the second example ^
is used both for matching at the beginning of input and for creating negated or complemented character class when used within groups.
let fruits = ["Apple", "Watermelon", "Orange", "Avocado", "Strawberry"];
// Selecting fruits that do not start by 'A' with a /^[^A]/ regex.
// In this example, two meanings of '^' control symbol are represented:
// 1) Matching beginning of the input
// 2) A negated or complemented character class: [^A]
// That is, it matches anything that is not enclosed in the brackets.
let fruitsStartsWithNotA = fruits.filter(fruit => /^[^A]/.test(fruit));
console.log(fruitsStartsWithNotA); // [ 'Watermelon', 'Orange', 'Strawberry' ]
Matching a word boundary
let fruitsWithDescription = ["Red apple", "Orange orange", "Green Avocado"];
// Select descriptions that contains 'en' or 'ed' words endings:
let enEdSelection = fruitsWithDescription.filter(descr => /(en|ed)\b/.test(descr));
console.log(enEdSelection); // [ 'Red apple', 'Green Avocado' ]
Lookahead assertion
// JS Lookahead assertion x(?=y)
let regex = /First(?= test)/g;
console.log('First test'.match(regex)); // [ 'First' ]
console.log('First peach'.match(regex)); // null
console.log('This is a First test in a year.'.match(regex)); // [ 'First' ]
console.log('This is a First peach in a month.'.match(regex)); // null
Basic negative lookahead assertion
For example, /\d+(?!\.)/
matches a number only if it is not followed by a decimal point. /\d+(?!\.)/.exec('3.141')
matches "141" but not "3.
console.log(/\d+(?!\.)/g.exec('3.141')); // [ '141', index: 2, input: '3.141' ]
Different meaning of '?!' combination usage in Assertions and Ranges
Different meaning of ?!
combination usage in Assertions /x(?!y)/
and Ranges [^?!]
.
let orangeNotLemon = "Do you want to have an orange? Yes, I do not want to have a lemon!";
// Different meaning of '?!' combination usage in Assertions /x(?!y)/ and Ranges /[^?!]/
let selectNotLemonRegex = /[^?!]+have(?! a lemon)[^?!]+[?!]/gi
console.log(orangeNotLemon.match(selectNotLemonRegex)); // [ 'Do you want to have an orange?' ]
let selectNotOrangeRegex = /[^?!]+have(?! an orange)[^?!]+[?!]/gi
console.log(orangeNotLemon.match(selectNotOrangeRegex)); // [ ' Yes, I do not want to have a lemon!' ]
Lookbehind assertion
let oranges = ['ripe orange A ', 'green orange B', 'ripe orange C',];
let ripe_oranges = oranges.filter( fruit => fruit.match(/(?<=ripe )orange/));
console.log(ripe_oranges); // [ 'ripe orange A ', 'ripe orange C' ]