JavaScript RegExp /v Flag: Unicode Sets, Intersections, and Emoji | JavaScript Tools Blog<br>Skip to content<br>Language EN RU ES FR DE IT PT 中文 日本語 AR
BLOG INDEX<br>The /v flag gives JavaScript regular expressions a much better way to work with Unicode.
You can intersect and subtract character sets, nest classes, and match certain Unicode properties that represent complete strings rather than single code points. If you have ever tried to validate multilingual input, detect non-ASCII digits, or count emoji without turning the regex into a puzzle box, this is the feature that finally makes some of those patterns readable.
If you have used the /u flag before, /v may look like a slightly more capable version of the same thing. It is not quite that. The /v flag enables Unicode Sets mode, which changes what can be expressed inside character classes and makes some previously awkward patterns surprisingly direct.
QUICK ANSWER<br>Use /v when your regular expression is really about set logic: letters from a script, Unicode digits except ASCII digits, characters that belong to two properties at once, or recognized emoji sequences.
What the /v flag does
The /v flag enables Unicode Sets mode.
A simple expression still looks familiar:
const regex = /\p{Letter}/v;
console.log(regex.test("A")); // true<br>console.log(regex.test("Ж")); // true<br>console.log(regex.test("7")); // false<br>But /v is not just an alternative spelling for /u. The two modes are separate, so you cannot combine them:
// SyntaxError<br>const regex = /hello/uv;<br>With /v, character classes gain several useful features:
set intersection with &&
set subtraction with --
nested character classes
Unicode properties of strings
more consistent case-insensitive matching for complemented properties
The real benefit becomes clearer once the pattern has to describe more than one condition.
Intersection with &&
Suppose we want Unicode characters that satisfy two conditions at once.
For example, we want letters associated with the Greek script, not every character that happens to belong to that script. With /v, we can intersect the two sets:
const greekLetters =<br>/[\p{Script_Extensions=Greek}&&\p{Letter}]/v;
console.log(greekLetters.test("π")); // true<br>console.log(greekLetters.test("β")); // true<br>console.log(greekLetters.test("A")); // false<br>console.log(greekLetters.test("7")); // false<br>Read the class as:
Greek characters<br>AND<br>letters<br>This is one of the nicest parts of Unicode Sets. Instead of maintaining large ranges manually or building the same condition with additional assertions, the regular expression describes the set we actually care about.
Why Script_Extensions matters
Unicode provides both Script and Script_Extensions.
They are not identical.
Script describes the primary script associated with a character. Script_Extensions can include characters that are legitimately used by several scripts. For validation and text processing, that distinction can matter because real user input is usually messier than a neat table of code points.
The useful part here is not memorizing every Unicode property. It is that /v lets us combine those properties directly when the distinction becomes important.
Subtracting one set from another
Set subtraction uses --.
Here is a practical example:
const nonAsciiDigit =<br>/[\p{Decimal_Number}--[0-9]]/v;
console.log(nonAsciiDigit.test("٤")); // true<br>console.log(nonAsciiDigit.test("७")); // true<br>console.log(nonAsciiDigit.test("4")); // false<br>\p{Decimal_Number} represents Unicode decimal digits.
Then we subtract:
0-9<br>So the final set means:
Unicode decimal digits<br>MINUS<br>ASCII digits<br>This can be useful when handling international user input. A field may ultimately need ASCII digits, but a user can enter visually valid decimal digits from another numbering system. Instead of treating that input as mysterious garbage later, you can detect the condition immediately.
function hasNonAsciiDigits(value) {<br>return /[\p{Decimal_Number}--[0-9]]/v.test(value);
console.log(hasNonAsciiDigits("12345")); // false<br>console.log(hasNonAsciiDigits("١٢٣٤٥")); // true<br>Now the application can decide whether to reject the input, normalize it, or explain the expected format.
Union is still simple
Not every set operation needs an operator.
Putting several alternatives inside the same class creates a union:
const lettersOrNumbers =<br>/[\p{Letter}\p{Number}]/v;
console.log(lettersOrNumbers.test("A")); // true<br>console.log(lettersOrNumbers.test("9")); // true<br>console.log(lettersOrNumbers.test("!")); // false<br>The mental model is:
[A B] union<br>[A&&B] intersection<br>[A--B] subtraction<br>That makes surprisingly complicated validation rules easier to describe.
OLDER APPROACH<br>Ranges, lookaheads, and custom lists<br>+Manual character ranges that are easy to miss or overmatch<br>+Large validation regexes that nobody wants to review<br>+Separate checks for rules that are really set relationships<br>+Emoji handling that often counts code points instead of visible sequences
/V...