Flags are letters placed after the closing slash that change how the whole pattern behaves: find every match instead of one, ignore case, treat each line separately, and so on. You can combine as many as you need, in any order.
/pattern/flags
/cat/gi // global + ignore case
new RegExp("cat", "gi") // same thing with the constructor
| Flag | Name | Effect |
|---|---|---|
| g | global | Find all matches, not just the first |
| i | ignore case | A matches a |
| m | multiline | ^ and $ match at each line, not just the whole text |
| s | dotAll | . also matches line breaks |
| u | unicode | Treat emoji etc. as single characters; enables \p{...} |
| y | sticky | Match only exactly at lastIndex |
| d | indices | Report start/end positions of matches |
| v | unicodeSets | An upgraded u (new in 2024): set math inside [ ] |
The first three, g, i, and m, cover nearly everything you will need.
const text = "red, green, red, blue";
text.replace(/red/, "RED") // "RED, green, red, blue" first only
text.replace(/red/g, "RED") // "RED, green, RED, blue" all
text.match(/red/) // ["red"] (plus extra info: index, input)
text.match(/red/g) // ["red", "red"] just the matches
/hello/.test("Hello World") // false
/hello/i.test("Hello World") // true
"JS js Js jS".match(/js/gi) // ["JS", "js", "Js", "jS"]
Normally ^ means "start of the text" and $ means "end of the text." With m, they mean start and end of each line:
const list = "apple\nbanana\navocado";
list.match(/^a\w+/g) // ["apple"] only the very start
list.match(/^a\w+/gm) // ["apple", "avocado"] start of every line
const note = "Start\nEnd";
/Start.End/.test(note) // false (. does not match the line break)
/Start.End/s.test(note) // true
"😀".match(/./g).length // 2 (split the emoji in half)
"😀".match(/./gu).length // 1
u is a good habit whenever text might contain emoji or non-English letters. It also unlocks \p{L} ("any letter in any language"), covered in RegExp Classes.
The d flag does not change what matches. It adds an indices property to the result, holding the [start, end] position of the match (and of each group, covered in RegExp Groups). The end is one past the last character, just like slice:
const result = "Order 42".match(/\d+/d);
console.log(result[0], result.indices[0]);
Every regex has a lastIndex property. With y, the match must start exactly at lastIndex: no searching ahead.
const sticky = /\w+/y;
sticky.lastIndex = 4;
console.log("abc def ghi".match(sticky)[0]); // starts right at position 4
sticky.lastIndex = 3;
console.log("abc def ghi".match(sticky)); // position 3 is a space: fail
const plain = /\w+/;
plain.lastIndex = 4;
console.log("abc def ghi".match(plain)[0]); // without y, lastIndex is ignored
Sticky matching is mainly used to write tokenizers: programs that read text one piece at a time, like the part of a browser that reads your JavaScript.
v is an upgraded u. Everything u does still works, and it adds set math inside square brackets. -- means "minus":
// lowercase letters, minus the vowels
console.log("hello world".match(/[[a-z]--[aeiou]]/gv).join(""));
You can use u or v, but not both: /x/uv is SyntaxError: Invalid regular expression flags.
Newer browsers let you turn a flag on for just one group with (?flags:...):
const re = /(?i:w3schools) tutorials/; // i applies only inside the group
console.log(re.test("W3SCHOOLS tutorials")); // true: the group ignores case
console.log(re.test("W3Schools Tutorials")); // false: "tutorials" still needs lowercase
const re = /x/gi;
re.flags // "gi"
re.global // true
re.ignoreCase // true
re.multiline // false
There is one true/false property per flag:
| global | g | hasIndices | d |
| ignoreCase | i | dotAll | s |
| multiline | m | sticky | y |
| unicode | u | unicodeSets | v |
/i example says it searches for "w3schools" but the code uses /is/g./(?i:WShools) tutorials/ is labeled "Returns true," but the typo (no 3, no c) makes it return false./\p{Emoji}/ fails "without the /v flag." It fails without u or v: /\p{Emoji}/u works fine.regex.exec() "returns an Iterator." It returns one match array (or null). matchAll() is the one that returns an iterator (RegExp Methods).A regex with g remembers where its last match ended, in a property called lastIndex. Calling test() repeatedly continues from there:
const re = /a/g;
re.test("a") // true (lastIndex moves to 1)
re.test("a") // false (starts searching at position 1: nothing there)
re.test("a") // true (lastIndex had reset to 0)
g flag on a regex you only call test() with. g is for match, replace, and matchAll.
What does this log?
console.log("Cat cat CAT".match(/cat/g).length, "Cat cat CAT".match(/cat/gi).length);
1 3. Without i, only the lowercase "cat" matches.Which flag makes ^ match at the start of every line?
gsmym is multiline. s is the one that lets . match line breaks, which is easy to mix up.Why does the second call return false?
const re = /a/g;
re.test("a"); // true
re.test("a"); // false
g, the regex remembers lastIndex (1 after the first match) and starts the next search there, past the end of "a". Drop the g when you only use test().^ and mg"👋🏽hi" with /./g and with /./gu