国际化字符

由于 JavaScript 最初的实现非常简单,而且这种简单的处理方式后来也成了标准,因此 JavaScript 正则表达式处理非英语字符时非常无力。例如,就 JavaScript 的正则表达式而言,“单词字符”只是 26 个拉丁字母(大写和小写)和数字,而且由于某些原因还包括下划线字符。像αβ这种明显的单词字符,则无法匹配\w(会匹配大写的\W,因为它们属于非单词字符)。

由于奇怪的历史性意外,\s(空白字符)则没有这种问题,会匹配所有 Unicode 标准中规定的空白字符,包括不间断空格和蒙古文元音分隔符。

另一个问题是,默认情况下,正则表达式使用代码单元,而不是实际的字符,正如第 5 章中所讨论的那样。 这意味着由两个代码单元组成的字符表现很奇怪。

  1. console.log(/\ud83c\udf4e{3}/.test("\ud83c\udf4e\ud83c\udf4e\ud83c\udf4e"));
  2. // → false
  3. console.log(/<.>/.test("<\ud83c\udf39>"));
  4. // → false
  5. console.log(/<.>/u.test("<\ud83c\udf39>"));
  6. // → true

问题是第一行中的"\ud83c\udf4e"(emoji 苹果)被视为两个代码单元,而{3}部分仅适用于第二个。 与之类似,点匹配单个代码单元,而不是组成玫瑰 emoji 符号的两个代码单元。

你必须在正则表达式中添加一个u选项(表示 Unicode),才能正确处理这些字符。 不幸的是,错误的行为仍然是默认行为,因为改变它可能会导致依赖于它的现有代码出现问题。

尽管这是刚刚标准化的,在撰写本文时尚未得到广泛支持,但可以在正则表达式中使用\p(必须启用 Unicode 选项)以匹配 Unicode 标准分配了给定属性的所有字符。

  1. console.log(/\p{Script=Greek}/u.test("α"));
  2. // → true
  3. console.log(/\p{Script=Arabic}/u.test("α"));
  4. // → false
  5. console.log(/\p{Alphabetic}/u.test("α"));
  6. // → true
  7. console.log(/\p{Alphabetic}/u.test("!"));
  8. // → false

Unicode 定义了许多有用的属性,尽管找到你需要的属性可能并不总是没有意义。 你可以使用\p{Property=Value}符号来匹配任何具有该属性的给定值的字符。 如果属性名称保持不变,如\p{Name}中那样,名称被假定为二元属性,如Alphabetic,或者类别,如Number