curriculum/challenges/english/blocks/lecture-working-with-regular-expressions/6733c5ba834ded4bb067e67c.md
Modifiers, often referred to as "flags", modify the behavior of a regular expression. Let's recall our example from an earlier lesson:
:::interactive_editor
const regex = /freeCodeCamp/;
console.log(regex.test("freeCodeCamp")); // true
console.log(regex.test("freeCodeCamp is great")); // true
console.log(regex.test("I love freeCodeCamp")); // true
console.log(regex.test("freecodecamp")); // false
console.log(regex.test("FREECODECAMP")); // false
console.log(regex.test("free")); // false
console.log(regex.test("code")); // false
console.log(regex.test("camp")); // false
:::
If you remember, the all-lowercase and all-uppercase freeCodeCamp strings failed to match the pattern. This is because, by default, regular expressions are case-sensitive.
But what if we could tell the regular expression to be case-insensitive? Well, there's a modifier for that. The i flag makes a regex ignore case. How can we use it? Flags go after the closing forward slash in a regular expression:
const regex = /freeCodeCamp/i;
Notice the change to the regular expression on the first line. Now we can check how this changes things:
:::interactive_editor
const regex = /freeCodeCamp/i;
console.log(regex.test("freeCodeCamp")); // true
console.log(regex.test("freeCodeCamp is great")); // true
console.log(regex.test("I love freeCodeCamp")); // true
console.log(regex.test("freecodecamp")); // true
console.log(regex.test("FREECODECAMP")); // true
console.log(regex.test("free")); // false
console.log(regex.test("code")); // false
console.log(regex.test("camp")); // false
:::
Because our regular expression is now case-insensitive, the all-lowercase and all-uppercase strings have "passed" the test. This can also work for a string with a random mix of uppercase and lowercase letters:
:::interactive_editor
const regex = /freeCodeCamp/i;
console.log(regex.test("dO yOu LoVe fReEcOdEcAmP?")); // true
:::
There are quite a few other flags that you can use. The g flag, or global modifier, allows your regular expression to match a pattern more than once.
Let's see how that affects our code. You'll notice we kept the i flag – a regular expression can use multiple flags (as many as needed) to achieve your desired behavior:
const regex = /freeCodeCamp/gi;
Wait a second... what's this? It would seem that the global modifier is making some of our strings that should be passing fail instead:
:::interactive_editor
const regex = /freeCodeCamp/gi;
console.log(regex.test("freeCodeCamp")); // true
console.log(regex.test("freeCodeCamp is great")); // false
console.log(regex.test("I love freeCodeCamp")); // true
console.log(regex.test("freecodecamp")); // false
console.log(regex.test("FREECODECAMP")); // true
console.log(regex.test("free")); // false
console.log(regex.test("code")); // false
console.log(regex.test("camp")); // false
:::
Why? Well, the global modifier makes your regular expression stateful. This means it keeps track of where it has previously matched a pattern. So when it matches the first freeCodeCamp string, it remembers that it found a match starting at index 0.
We then test it against freeCodeCamp is great, but it doesn't start at index 0. The regular expression "knows" it found a match at index 0 already, so even though this is a different string, it starts from the end index of the match.
freeCodeCamp is 12 characters long, so a match at 0 ends at index 11. The matching will resume at index 12. And since is great does not match freeCodeCamp, it returns false.
Then, because it fails to find a match, it "loses" its state and starts the following match back at 0.
If we switch our logs around so that a string with the match at 0 is followed immediately by a string that has a match later than index 11:
:::interactive_editor
const regex = /freeCodeCamp/gi;
console.log(regex.test("freeCodeCamp")); // true
console.log(regex.test("I loooooooove freeCodeCamp")); // true
:::
When a regular expression is global, it gets a new property called lastIndex. Grabbing our previous code, let's see how this property works:
:::interactive_editor
const regex = /freeCodeCamp/gi;
console.log(regex.lastIndex); // 0
console.log(regex.test("freeCodeCamp")); // true
console.log(regex.lastIndex); // 12
console.log(regex.test("freeCodeCamp is great")); // false
console.log(regex.lastIndex); // 0
console.log(regex.test("I love freeCodeCamp")); // true
console.log(regex.lastIndex); // 19
console.log(regex.test("freecodecamp")); // false
console.log(regex.lastIndex); // 0
console.log(regex.test("FREECODECAMP")); // true
console.log(regex.lastIndex); // 12
console.log(regex.test("free")); // false
console.log(regex.lastIndex); // 0
console.log(regex.test("code")); // false
console.log(regex.lastIndex); // 0
console.log(regex.test("camp")); // false
:::
Looking at this example, you can see how the state of the regular expression changes with each test call using the lastIndex to track its previous matches.
The global flag is great when you need to get multiple matches from a single string. But if you're testing multiple strings with the same regular expression it's best to leave the g flag off.
Before learning about the next flag, you need to learn about anchors. The caret (^) anchor, at the beginning of the regular expression, says "match the start of the string":
const start = /^freecodecamp/i;
The dollar sign ($) anchor, at the end of the regular expression, says "match the end of the string":
const end = /freecodecamp$/i;
Take a moment to compare the outputs on the right:
:::interactive_editor
const start = /^freecodecamp/i;
const end = /freecodecamp$/i;
console.log(start.test("freecodecamp")); // true
console.log(end.test("freecodecamp")); // true
console.log(start.test("freecodecamp is great")); // true
console.log(end.test("freecodecamp is great")); // false
console.log(start.test("i love freecodecamp")); // false
console.log(end.test("i love freecodecamp")); // true
console.log(start.test("have met freecodecamp's founder")); // false
console.log(end.test("have met freecodecamp's founder")); // false
:::
See how the start anchor only matches at the beginning of the string, and the end anchor only matches at the end of the string? But what about matching across multiple lines? Let's take a look at that:
:::interactive_editor
const start = /^freecodecamp/i;
const end = /freecodecamp$/i;
const string = `I really love
freecodecamp
it's my favorite`;
console.log(start.test(string)); // false
console.log(end.test(string)); // false
:::
Even though freecodecamp is in there on its own line, it fails both tests. This is because, by default, anchors look for the beginning and end of the entire string.
But you can make a regex handle multiple lines with the m flag, or the multi-line modifier. Let's add that to our regular expressions to see what we get:
:::interactive_editor
const start = /^freecodecamp/im;
const end = /freecodecamp$/im;
const string = `I really love
freecodecamp
it's my favorite`;
console.log(start.test(string)); // true
console.log(end.test(string)); // true
:::
Now they both match! Because the freecodecamp is entirely on its own line, the start anchor matches the beginning of that line, and the end anchor matches the end of that line.
Finally, you have the d flag, or indices modifier. Remember that the i flag is for case-insensitivity, so the indices modifier needed a different flag.
The d flag expands the information you get in a match object. Let's add it to our regular expression:
const regex = /freecodecamp/di;
const string = "we love freecodecamp isn't freecodecamp great?";
console.log(string.match(regex));
And the result is:
// [
// 'freecodecamp',
// index: 8,
// input: "we love freecodecamp isn't freecodecamp great?",
// groups: undefined,
// indices: [
// 0: [8, 20],
// groups: undefined
// ]
// ]
Our match object gets a new indices property! This property is an array of two numbers, the first being the index in the original string where the match starts, and the second being the index after the match ended. This array also has an extra groups property, which is also for named capture groups.
There are a few other flags that you should know are available to you, but are less common in typical code.
The first is the unicode modifier, or u flag. This expands the functionality of a regular expression to allow it to match special unicode characters.
You'll learn more about character classes in a future lesson, but the u flag gives you access to special classes like Extended_Pictographic to match most emoji:
:::interactive_editor
const regex = /🍎/u;
const str = "I have an apple 🍎";
console.log(regex.test(str)); // true
:::
There is also a v flag, which further expands the functionality of the unicode matching.
The second is the sticky modifier, or the y flag. The sticky modifier behaves very similarly to the global modifier, but with a few exceptions.
The biggest one is that a global regular expression will start from lastIndex and search the entire remainder of the string for another match, but a sticky regular expression will return null and reset the lastIndex to 0 if there is not immediately a match at the previous lastIndex.
And the last is the single-line modifier, or the s flag. Remember that the multiline modifier allows start and end anchors to match the start and end of a line, instead of the entire string.
The single-line modifier allows a wildcard character, represented by a period (.) in regex, to match linebreaks – effectively treating the string as a single line of text.
There are quite a few of these modifiers, but the i and g flags are the ones you'll use most frequently, and are the most important to remember.
What would the following code output?
const regex = /freecodecamp/i;
console.log(regex.test("I love FREECODECAMP!"));
console.log(regex.test("freeCodoCamp"));
console.log(regex.test("We went freeCodeCamping."));
true
true
true
The i flag makes the regex case-insensitive, so freeCodeCamp matches regardless of case, as long as the letters are the same.
true
false
true
true
true
false
The i flag makes the regex case-insensitive, so freeCodeCamp matches regardless of case, as long as the letters are the same.
false
false
false
The i flag makes the regex case-insensitive, so freeCodeCamp matches regardless of case, as long as the letters are the same.
2
When would you NOT want to use the global (g) flag in a regular expression?
When you want to match a pattern multiple times within a single string.
The g flag is stateful, meaning it tracks the last match, which can cause issues when testing multiple strings.
When you want the match to start fresh with each new test.
The g flag is stateful, meaning it tracks the last match, which can cause issues when testing multiple strings.
When you want to make the regex case-insensitive.
The g flag is stateful, meaning it tracks the last match, which can cause issues when testing multiple strings.
When you are testing multiple strings and don't need to track match state.
4
What does the multi-line (m) modifier do in a regular expression?
It allows anchors (^ and $) to match the start and end of each line, not just the entire string.
It makes the regular expression case-insensitive.
The m modifier enables matching at the start and end of lines in multi-line strings.
It allows the regular expression to match linebreaks.
The m modifier enables matching at the start and end of lines in multi-line strings.
It makes the regular expression match globally.
The m modifier enables matching at the start and end of lines in multi-line strings.
1