Unicode property escapes

Unicode property escapes 正则表达式 支持根据 Unicode 属性进行匹配,例如我们可以用它来匹配出表情、标点符号、字母 (甚至适用特定语言或文字) 等。同一符号可以拥有多种 Unicode 属性,属性则有 binary ("boolean-like") 和 non-binary 之分。

尝试一下

**备注:**使用 Unicode 属性转义依靠 \u 标识\u 表示该字符串被视为一串 Unicode 代码点。参考 RegExp.prototype.nicode.

备注: 某些 Unicode 属性比字符类(如 \w 只匹配拉丁字母 az) 包含更多的字符 ,但后者浏览器兼容性更好 (截至 2020 一月).

句法

// Non-binary 属性
\p{Unicode 属性值}
\p{Unicode 属性名=Unicode 属性值}

// Binary and non-binary 属性
\p{UnicodeBinary 属性名}

// \P 为 \p 取反
\P{Unicode 属性值}
\P{UnicodeBinary 属性名}

参考 PropertyValueAliases.txt

UnicodeBinary 属性名

Binary 属性名. E.g.: ASCII. Alpha, Math, Diacritic, Emoji, Hex_Digit, Math, White_space, 等。另见 Unicode Data PropList.txt.

Unicode 属性名

Non-binary 属性名:

Unicode 属性值

很多值有同名或简写 (e.g. 对应着 General_Category 属性名的属性值 Decimal_Number 可以写作 Nd, digit, 或 Decimal_Number). 大多数属性值的 Unicode 属性名 和等号可以省去。如果想明确某 Unicode 属性名,必须给出它的值。

备注: 因为可使用的属性和值太多,这里不一一赘述,仅提供几个例子。

基本原理

在 ES2018 之前,JavaScript 没有强有效的方式用匹配出不同文字(如马其顿语,希腊语,Georgian 等) 或不同 属性名 (如 Emoji 等) 的字符。另见 tc39 Proposal on Unicode Property Escapes.

例子

(一般类别)General categories

General categories 对 Unicode 字符进行分类,子类别用于精确定义类别。长名和简写的 Unicode 属性转义都可用。

它们可匹配字母、数字、符号、标点符号、空格等等。一般类别详见 the Unicode specification.

// finding all the letters of a text
let story = "It’s the Cheshire Cat: now I shall have somebody to talk to.";

// Most explicit form
story.match(/\p{General_Category=Letter}/gu);

// It is not mandatory to use the property name for General categories
story.match(/\p{Letter}/gu);

// This is equivalent (short alias):
story.match(/\p{L}/gu);

// This is also equivalent (conjunction of all the subcategories using short aliases)
story.match(/\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}/gu);

文字(Script)和文字扩充(Script_Extensions)

某些语言使用不同的文字,如英语和西班牙语使用拉丁文,而阿拉伯语和俄语用阿拉伯文和俄文。ScriptScript_Extensions Unicode 属性允许正则表达式根据字符所属的文字或该文字所属的文字扩充进行匹配。

比如,A 属于 拉丁文ε 属于希腊 (Greek)文。

let mixedCharacters = "aεЛ";

// Using the canonical "long" name of the script
mixedCharacters.match(/\p{Script=Latin}/u); // a

// Using a short alias for the script
mixedCharacters.match(/\p{Script=Grek}/u); // ε

// Using the short name Sc for the Script property
mixedCharacters.match(/\p{Sc=Cyrillic}/u); // Л

详见 the Unicode specificationScripts table in the ECMAScript specification.

某字符用于多种文字时,Script 优先匹配最主要使用那个字符的文字。如果想要根据非主要的文字进行匹配,我们可以使用 Script_Extensions 属性 (简写为Scx).

// ٢ is the digit 2 in Arabic-Indic notation
// while it is predominantly written within the Arabic script
// it can also be written in the Thaana script

"٢".match(/\p{Script=Thaana}/u);
// null as Thaana is not the predominant script        super()

"٢".match(/\p{Script_Extensions=Thaana}/u);
// ["٢", index: 0, input: "٢", groups: undefined]

Unicode 属性转义 vs. 字符类

JavaScript 正则表达式可以使用 字符类 尤其是 \w\d 匹配字母或数字,然而,这样的形式只匹配拉丁文字的字符 (换言之,azAZ\w09\d),见例子,这样的使用放到非拉丁文本中是有些蠢的。

Unicode 属性转义 categories 包含更多字符, \p{Letter}\p{Number} 将会适用于任何文字。

// Trying to use ranges to avoid \w limitations:

const nonEnglishText = "Приключения Алисы в Стране чудес";
const regexpBMPWord = /([\u0000-\u0019\u0021-\uFFFF])+/gu;
// BMP goes through U+0000 to U+FFFF but space is U+0020

console.table(nonEnglishText.match(regexpBMPWord));

// Using Unicode property escapes instead
const regexpUPE = /\p{L}+/gu;
console.table(nonEnglishText.match(regexpUPE));

See also