迹忆客 专注技术分享

当前位置:主页 > 学无止境 > WEB前端 > JavaScript >

JavaScript 正则表达式中的 Unicode 属性转义

作者:迹忆客 最近更新:2023/01/08 浏览次数:

ES2018 为 JavaScript 正则表达式添加了对形式为 \p{...}\P{...} 的 Unicode 属性转义的支持。

本文解释了 Unicode 属性转义是什么、它们如何工作以及它们为何有用。


介绍

Unicode 标准为每个符号分配了各种属性和属性值。 例如,要获取希腊文字中使用的符号集,请在 Unicode 数据库中搜索其 Script_Extensions 属性值包括希腊语的符号。

Unicode 属性转义使得在 ECMAScript 正则表达式中访问这些 Unicode 字符属性成为可能。 例如,模式 \p{Script_Extensions=Greek} 匹配希腊文字中使用的每个符号。

const regexGreekSymbol = /\p{Script_Extensions=Greek}/u;
regexGreekSymbol.test('π');
// → true

以前,希望在 JavaScript 中使用等效正则表达式的开发人员不得不求助于大型运行时依赖项或构建脚本,这两者都会导致性能和可维护性问题。 通过对 Unicode 属性转义的内置支持,创建基于 Unicode 属性的正则表达式再简单不过了。


Api

为了获得最佳的向后兼容性,Unicode 属性转义仅在设置了 u 标志的正则表达式中可用。

非二进制属性

非二进制 Unicode 属性的 Unicode 属性转义使用以下语法:

\p{UnicodePropertyName=UnicodePropertyValue}

当前提案保证支持以下非二进制 Unicode 属性及其值:General_CategoryScriptScript_Extensions

\p{General_Category=Decimal_Number}
\p{Script=Greek}
\p{Script_Extensions=Greek}

对于 General_Category 值,可以省略 General_Category= 部分。

\p{General_Category=Decimal_Number}
\p{Decimal_Number}

二进制属性

尝试通过为二进制属性指定值来使用上述语法会触发语法错误。 由于二进制 Unicode 属性只有两个可能的值(是或否),因此我们只需指定属性名称。 使用 \p{...} 匹配具有属性 (Yes) 的符号,使用 \P{...} 匹配否定集 (No)。

\p{White_Space}
\P{White_Space}

当前提案保证支持可用二进制 Unicode 属性的子集,包括(但不限于)UTS18 RL1.2 所需的属性:ASCIIAlphabeticAnyAssignedDefault_Ignorable_Code_PointLowercaseNoncharacter_Code_PointUppercase White_Space 等 。

请注意 ,这包括 UTR51 中定义的二进制属性:EmojiEmoji_ComponentEmoji_PresentationEmoji_ModifierEmoji_Modifier_Base

属性和值别名

可以使用 PropertyAliases.txtPropertyValueAliases.txt 中定义的别名来代替规范的属性和值名称。 我不建议这样做,因为它会使模式更难阅读。

使用未知的属性名称或值会触发 SyntaxError


示例

匹配表情符号

为了匹配表情符号,UTR51 的二进制属性会派上用场。

const regex = /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu;

这个正则表达式匹配,从左到右:

  1. 带有可选修饰符的表情符号 (\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?);
  2. 默认情况下呈现为表情符号而不是文本的任何剩余符号 (\p{Emoji_Presentation});
  3. 默认呈现为文本的符号,但使用 U+FE0F VARIATION SELECTOR-16 (\p{Emoji}\uFE0F) 强制呈现为表情符号。
const regex = /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu;
const text = `
\u{231A}: ⌚ default emoji presentation character (Emoji_Presentation)
\u{2194}\u{FE0F}: ↔️ default text presentation character rendered as emoji
\u{1F469}: 👩 emoji modifier base (Emoji_Modifier_Base)
\u{1F469}\u{1F3FF}: 👩🏿 emoji modifier base followed by a modifier
`;

let match;
while (match = regex.exec(text)) {
    const emoji = match[0];
    console.log(`Matched sequence ${ emoji } — code points: ${ [...emoji].length }`);
}

终端输出

Matched sequence ⌚ — code points: 1
Matched sequence ⌚ — code points: 1
Matched sequence ↔️ — code points: 2
Matched sequence ↔️ — code points: 2
Matched sequence 👩 — code points: 1
Matched sequence 👩 — code points: 1
Matched sequence 👩🏿 — code points: 2
Matched sequence 👩🏿 — code points: 2

有关匹配表情符号序列和 ZWJ 序列的更完整解决方案,请参阅 emoji-regex。 后续提案使用新功能扩展了 Unicode 属性转义,以便更轻松地执行诸如匹配表情符号之类的操作。

\w 的 Unicode 识别版本

要匹配 Unicode 中的任何文字符号而不仅仅是 ASCII [a-zA-Z0-9_],请使用 [\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}] 作为 根据 UTS18。

const regex = /([\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]+)/gu;
const text = `
Amharic: የኔ ማንዣበቢያ መኪና በዓሣዎች ተሞልቷል
Bengali: আমার হভারক্রাফ্ট কুঁচে মাছ-এ ভরা হয়ে গেছে
Georgian: ჩემი ხომალდი საჰაერო ბალიშზე სავსეა გველთევზებით
Macedonian: Моето летачко возило е полно со јагули
Vietnamese: Tàu cánh ngầm của tôi đầy lươn
`;

let match;
while (match = regex.exec(text)) {
    const word = match[1];
    console.log(`Matched word with length ${ word.length }: ${ word }`);
}

终端输出

Matched word with length 7: Amharic
Matched word with length 2: የኔ
Matched word with length 6: ማንዣበቢያ
Matched word with length 3: መኪና
Matched word with length 5: በዓሣዎች
Matched word with length 5: ተሞልቷል
Matched word with length 7: Bengali
Matched word with length 4: আমার
Matched word with length 11: হভারক্রাফ্ট
Matched word with length 5: কুঁচে
Matched word with length 3: মাছ
Matched word with length 1: এ
Matched word with length 3: ভরা
Matched word with length 3: হয়ে
Matched word with length 4: গেছে
Matched word with length 8: Georgian
Matched word with length 4: ჩემი
Matched word with length 7: ხომალდი
Matched word with length 7: საჰაერო
Matched word with length 7: ბალიშზე
Matched word with length 6: სავსეა
Matched word with length 12: გველთევზებით
Matched word with length 10: Macedonian
Matched word with length 5: Моето
Matched word with length 7: летачко
Matched word with length 6: возило
Matched word with length 1: е
Matched word with length 5: полно
Matched word with length 2: со
Matched word with length 6: јагули
Matched word with length 10: Vietnamese
Matched word with length 3: Tàu
Matched word with length 4: cánh
Matched word with length 4: ngầm
Matched word with length 3: của
Matched word with length 3: tôi
Matched word with length 3: đầy
Matched word with length 4: lươn

\d 的 Unicode 识别版本

要匹配 Unicode 中的任何十进制数字而不仅仅是 ASCII [0-9],请使用 \p{Decimal_Number} 而不是按照 UTS18 的 \d

const regex = /^\p{Decimal_Number}+$/u;
regex.test('𝟏𝟐𝟑𝟜𝟝𝟞𝟩𝟪𝟫𝟬𝟭𝟮𝟯𝟺𝟻𝟼');
// → true

要匹配 Unicode 中的任何数字符号,包括非十进制符号,如罗马数字,请使用 \p{Number}

const regex = /^\p{Number}+$/u;
regex.test('²³¹¼½¾𝟏𝟐𝟑𝟜𝟝𝟞𝟩𝟪𝟫𝟬𝟭𝟮𝟯𝟺𝟻𝟼㉛㉜㉝ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿ');
// → true

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便