mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-09-24 23:01:18 +08:00
feat(curriculum): add interactive examples to regex modifiers lesson (#63763)
Co-authored-by: Almee Christian <almee@Almees-MacBook-Pro.local>
This commit is contained in:
co-authored by
Almee Christian
parent
89884f4de2
commit
069ccd361b
+51
-1
@@ -5,10 +5,12 @@ challengeType: 19
|
||||
dashedName: what-are-some-common-regular-expression-modifiers-used-for-searching
|
||||
---
|
||||
|
||||
# --description--
|
||||
# --interactive--
|
||||
|
||||
Modifiers, often referred to as "flags", modify the behavior of a regular expression. Let's recall our example from an earlier lesson:
|
||||
|
||||
:::interactive_editor
|
||||
|
||||
```js
|
||||
const regex = /freeCodeCamp/;
|
||||
console.log(regex.test("freeCodeCamp")); // true
|
||||
@@ -21,6 +23,8 @@ 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:
|
||||
@@ -31,7 +35,11 @@ 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
|
||||
|
||||
```js
|
||||
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
|
||||
@@ -42,12 +50,20 @@ 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
|
||||
|
||||
```js
|
||||
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:
|
||||
@@ -58,7 +74,11 @@ 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
|
||||
|
||||
```js
|
||||
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
|
||||
@@ -69,6 +89,8 @@ 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.
|
||||
@@ -79,14 +101,24 @@ Then, because it fails to find a match, it "loses" its state and starts the foll
|
||||
|
||||
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
|
||||
|
||||
```js
|
||||
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
|
||||
|
||||
```js
|
||||
const regex = /freeCodeCamp/gi;
|
||||
|
||||
console.log(regex.lastIndex); // 0
|
||||
console.log(regex.test("freeCodeCamp")); // true
|
||||
console.log(regex.lastIndex); // 12
|
||||
@@ -105,6 +137,8 @@ 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.
|
||||
@@ -123,6 +157,8 @@ const end = /freecodecamp$/i;
|
||||
|
||||
Take a moment to compare the outputs on the right:
|
||||
|
||||
:::interactive_editor
|
||||
|
||||
```js
|
||||
const start = /^freecodecamp/i;
|
||||
const end = /freecodecamp$/i;
|
||||
@@ -136,8 +172,12 @@ 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
|
||||
|
||||
```js
|
||||
const start = /^freecodecamp/i;
|
||||
const end = /freecodecamp$/i;
|
||||
@@ -148,10 +188,14 @@ 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
|
||||
|
||||
```js
|
||||
const start = /^freecodecamp/im;
|
||||
const end = /freecodecamp$/im;
|
||||
@@ -162,6 +206,8 @@ 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.
|
||||
@@ -197,6 +243,8 @@ The first is the unicode modifier, or `u` flag. This expands the functionality o
|
||||
|
||||
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
|
||||
|
||||
```js
|
||||
const regex = /🍎/u;
|
||||
|
||||
@@ -204,6 +252,8 @@ 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.
|
||||
|
||||
Reference in New Issue
Block a user