SymbolFYI

Regex Unicode Support

Programming & Dev
定义

Using Unicode-aware regular expressions with flags like /u in JS and re.UNICODE in Python.

Unicode-Aware Regular Expressions

Regular expressions have historically operated on bytes or UTF-16 code units, producing incorrect results for Unicode text containing emoji, supplementary characters, or complex scripts. Modern regex engines and language-specific flags provide Unicode-aware matching through Unicode property escapes, script-based categories, and character class improvements.

The Problem with Naive Unicode Regex

// UTF-16: emoji as 2 code units
'😀'.match(/./g)   // ['\uD83D', '\uDE00'] — broken into surrogates
'😀'.length        // 2 — wrong for user-perceived characters

// Python 3: str is Unicode, but \w misses many scripts
import re
re.match(r'\w+', 'München')  # Matches: str is Unicode in Python 3
re.match(r'\w+', 'Привет')   # Matches Cyrillic
re.match(r'\w+', '日本語')    # Does NOT match by default

JavaScript: u and v Flags

The u flag (ES2015) enables Unicode-correct matching:

// u flag: . matches code points, not code units
/./u.test('😀')           // true (one code point)
/./.test('😀')            // also true, but matches first surrogate
/^.$/u.test('😀')         // true
/^.$/.test('😀')          // false

// u flag: character class ranges work correctly
/[\u{1F600}-\u{1F64F}]/u.test('😀')   // true (emoji range)

// Unicode property escapes (ES2018, requires u or v flag)
/\p{Emoji}/u.test('😀')              // true
/\p{Script=Latin}/u.test('A')        // true
/\p{Script=Cyrillic}/u.test('А')     // true
/\p{Script=Han}/u.test('日')         // true
/\p{Letter}/u.test('é')             // true
/\p{Number}/u.test('²')             // true
/\p{Uppercase_Letter}/u.test('A')   // true

// v flag (ES2024): Unicode sets — more powerful character classes
/[\p{Script=Latin}&&\p{Uppercase_Letter}]/v.test('A')  // true

Python: re and regex Modules

import re

# Python 3 str is Unicode; \w matches Unicode letters/digits
re.findall(r'\w+', 'café résumé')  # ['café', 'résumé']

# re.UNICODE flag is the default for str in Python 3
re.match(r'\w+', '日本語', re.UNICODE)  # None — \w doesn't match CJK

# For full Unicode property support, use the 'regex' package
import regex
regex.match(r'\p{Script=Han}+', '日本語')  # Matches
regex.match(r'\p{Emoji}', '😀')           # Matches
regex.match(r'\p{L}+', 'Привет')          # Matches any letter script

Common Unicode Property Escapes

Escape Matches
\p{Letter} or \p{L} Any letter in any script
\p{Uppercase_Letter} Uppercase letters
\p{Number} or \p{N} Any numeric character
\p{Emoji} Emoji characters
\p{Script=Latin} Latin script characters
\p{Script=Han} CJK unified ideographs
\p{Script=Arabic} Arabic script
\p{White_Space} Unicode whitespace
\p{Punctuation} Punctuation in any script

Grapheme Clusters in Regex

Neither JavaScript's u flag nor Python's re module natively handles grapheme clusters (user-perceived characters that may span multiple code points). For splitting text at grapheme boundaries:

// JavaScript: Intl.Segmenter for grapheme-aware splitting
const seg = new Intl.Segmenter('en', { granularity: 'grapheme' });
[...seg.segment('👨‍👩‍👧‍👦')].length  // 1
# Python: grapheme package for cluster-aware operations
import grapheme
grapheme.length('👨‍👩‍👧‍👦')  # 1
list(grapheme.graphemes('café'))  # ['c', 'a', 'f', 'é']

Practical Patterns

// Match a Unicode word (any script)
const wordPattern = /\p{Letter}[\p{Letter}\p{Number}]*/gu;

// Match emoji
const emojiPattern = /\p{Emoji_Presentation}/gu;

// Strip emoji from a string
str.replace(/\p{Emoji_Presentation}/gu, '');

// Validate that a string contains only letters and spaces
/^[\p{Letter}\s]+$/u.test(input);

相关符号

相关术语

相关工具

相关指南