Unicode: flag "u" and class \p{...}
JavaScript strings are stored as Unicode text. Under the hood, the engine works with UTF-16: each unit of storage is 2 bytes, and 2 bytes give you 65,536 possible values. That covers a huge amount of the world’s writing, but not all of it.
To reach beyond that limit, some characters are stored using two 2-byte units back to back — 4 bytes total. Mathematical symbols like 𝔸, emoji like 🚀, and many historical scripts live in that extended range.
Here are the code points of a few characters, and how many bytes each one takes in UTF-16:
| Character | Unicode | Bytes in UTF-16 |
|---|---|---|
| a | 0x0061 |
2 |
| ∑ | 0x2211 |
2 |
| 𝔸 | 0x1d538 |
4 |
| 𝔹 | 0x1d539 |
4 |
| 🚀 | 0x1f680 |
4 |
So a and ∑ fit in a single 2-byte unit, while 𝔸, 𝔹, and 🚀 each need two units glued together.
When JavaScript was designed, Unicode was smaller and 4-byte characters did not exist. Some parts of the language still carry that old assumption, and they miscount these characters.
The length property is the classic example. It counts code units, not characters:
alert('🚀'.length); // 2
alert('𝔸'.length); // 2
Your eyes see one character. length sees two, because it counts each 2-byte unit separately. For a surrogate pair that’s wrong — the two units are meaningless apart and should be treated as a single character. (The Strings article covers surrogate pairs in more depth.)
Regular expressions inherit the same default behavior: without help, they also chop a 4-byte character into two 2-byte halves. That leads to the same kind of surprises you get with length, and the Sets and ranges […] article shows where it bites in practice.
Type a string below and watch length (which counts 2-byte units) disagree with the number of characters you actually see. Try adding an emoji or a mathematical letter like 𝔸:
The fix is the pattern:u flag. Add it, and the regexp engine treats a surrogate pair as one character. It also switches on a second feature: Unicode property escapes, pattern:\p{…}, which is the main subject of this article.
Unicode properties \p{…}
Every character in Unicode carries a bundle of metadata — properties. They record which “category” the character falls into and other facts about it.
Two properties come up constantly:
Letter— the character is a letter in some alphabet, any language.Number— the character is a digit, whether Arabic, Chinese, or anything else.
You match a character by its property with pattern:\p{…}, and this only works when the pattern:u flag is present.
For example, pattern:\p{Letter} matches a letter in any script. L is an alias for Letter, so pattern:\p{L} does the same thing. Most properties have a short alias like this.
The example below pulls out three letters from three different writing systems — Latin, Greek, and Armenian:
let str = "Z Ω հ";
alert( str.match(/\p{L}/gu) ); // Z,Ω,հ
alert( str.match(/\p{L}/g) ); // null — \p needs the "u" flag to mean anything
Without pattern:u, the pattern:\p{L} syntax isn’t recognized as a property class, so the second match finds nothing.
Try it live below. The demo runs pattern:\p{L} against whatever you type and lists every letter it pulls out — regardless of alphabet. Digits, spaces, and punctuation are ignored:
Here are the top-level categories and their subcategories. Each one has a one- or two-letter code you can drop straight into pattern:\p{…}:
So if you want lowercase letters only, write pattern:\p{Ll}. For any punctuation mark, pattern:\p{P}. Passing just the top-level code (P) matches every subcategory under it; adding the second letter (Pd) narrows it to one.
Beyond the general categories there are derived properties — computed from other data — such as:
Alphabetic(Alpha): the union of LettersL, letter-numbersNl(like Ⅶ, the Roman numeral 7), and a set ofOther_Alphabetic(OAlpha) characters.Hex_Digit: the hexadecimal digits0-9,a-f, andA-F.- …and many more.
Unicode defines a long list of properties. Rather than reproduce it all, here are the reference sources:
- Every property of a single character: https://unicode.org/cldr/utility/character.jsp
- Every character with a given property: https://unicode.org/cldr/utility/list-unicodeset.jsp
- Short aliases for property names: https://www.unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt
- The full character database in text form: https://www.unicode.org/Public/UCD/latest/ucd/
Example: hexadecimal numbers
Say you want to find hex bytes written like xE0, where each character after the x is a hex digit (0–9 or A–F).
The pattern:\p{Hex_Digit} property matches exactly those digits:
let regexp = /x\p{Hex_Digit}\p{Hex_Digit}/u;
alert("byte: xC3".match(regexp)); // xC3
Two pattern:\p{Hex_Digit} in a row require two hex digits after the x. Because the property already knows the whole hex-digit set, you avoid spelling out a pattern:[0-9a-fA-F] character range by hand.
Example: Chinese characters
To search by writing system, Unicode has the Script property. Its values name scripts: Cyrillic, Greek, Arabic, Han (used for Chinese), and so on — here’s the full list.
You match a script with pattern:\p{Script=<value>}, or the short form pattern:\p{sc=<value>}. Cyrillic letters would be pattern:\p{sc=Cyrillic}; Chinese characters are pattern:\p{sc=Han}:
let regexp = /\p{sc=Han}/gu; // matches Han (Chinese) characters
let str = `Ciao Спасибо 山川 42_88`;
alert( str.match(regexp) ); // 山,川
The Latin Ciao, the Cyrillic Спасибо, and the digits are all skipped. Only the two Han characters 山 and 川 come back.
Example: currency
Currency signs like €, £, and ₹ share the property pattern:\p{Currency_Symbol}, aliased to pattern:\p{Sc}.
Combine it with pattern:\d to find prices in a “currency then a digit” shape:
let regexp = /\p{Sc}\d/gu;
let str = `Prices: €3, £5, ₹8`;
alert( str.match(regexp) ); // €3,£5,₹8
Each match is a currency symbol immediately followed by one digit. Matching multi-digit numbers needs quantifiers, which the Quantifiers +, *, ? and {n} article covers.
Here pattern:\p{Sc}\p{Nd}+ finds a currency symbol followed by one or more decimal digits, so it captures whole prices. Edit the text and add prices in any currency — the property class recognizes every symbol without you listing them:
Summary
The pattern:u flag turns on Unicode support in a regular expression, and that buys you two things:
- Correct 4-byte handling. A surrogate pair is matched as one character instead of two 2-byte halves.
- Property classes. You can search by Unicode property with
pattern:\p{…}.
With property classes you can target letters of a specific language, digits, punctuation, quotes, currency symbols, and much more — declaratively, without maintaining fragile hand-written character ranges.