方括号 […] 内的多个字符或字符类表示“搜索给定字符中的任何字符”。
集合
例如,[eao] 表示 3 个字符中的任何一个:'a'、'e' 或 'o'。
这被称为集合。集合可以在正则表达式中与普通字符一起使用
// find [t or m], and then "op"
alert( "Mop top".match(/[tm]op/gi) ); // "Mop", "top"
请注意,虽然集合中有多个字符,但它们对应于匹配中的一个字符。
因此,以下示例没有匹配项
// find "V", then [o or i], then "la"
alert( "Voila".match(/V[oi]la/) ); // null, no matches
该模式搜索
V,- 然后是字母
[oi]中的一个, - 然后是
la。
所以 Vola 或 Vila 会匹配。
范围
方括号也可以包含字符范围。
例如,[a-z] 是从 a 到 z 的范围内的字符,而 [0-5] 是从 0 到 5 的数字。
在下面的示例中,我们正在搜索 "x" 后面跟着两个数字或从 A 到 F 的字母
alert( "Exception 0xAF".match(/x[0-9A-F][0-9A-F]/g) ); // xAF
这里 [0-9A-F] 有两个范围:它搜索一个字符,该字符要么是 0 到 9 的数字,要么是 A 到 F 的字母。
如果我们想查找小写字母,我们可以添加 a-f 范围:[0-9A-Fa-f]。或者添加标志 i。
我们也可以在 […] 中使用字符类。
例如,如果我们想查找一个单词字符 \w 或一个连字符 -,那么集合是 [\w-]。
也可以组合多个类,例如 [\s\d] 表示“空格字符或数字”。
例如
- \d – 等同于
[0-9], - \w – 等同于
[a-zA-Z0-9_], - \s – 等同于
[\t\n\v\f\r ],以及其他一些罕见的 Unicode 空格字符。
示例:多语言 \w
由于字符类 \w 是 [a-zA-Z0-9_] 的简写,它无法找到汉字、西里尔字母等。
我们可以编写一个更通用的模式,它可以查找任何语言中的单词字符。使用 Unicode 属性很容易做到这一点:[\p{Alpha}\p{M}\p{Nd}\p{Pc}\p{Join_C}]。
让我们来解读它。类似于 \w,我们正在创建自己的集合,其中包含具有以下 Unicode 属性的字符
字母(Alpha) – 用于字母,Mark(M) – 用于重音符号,Decimal_Number(Nd) – 用于数字,Connector_Punctuation(Pc) – 用于下划线'_'和类似字符,Join_Control(Join_C) – 两个特殊代码200c和200d,用于连字,例如在阿拉伯语中。
使用示例
let regexp = /[\p{Alpha}\p{M}\p{Nd}\p{Pc}\p{Join_C}]/gu;
let str = `Hi 你好 12`;
// finds all letters and digits:
alert( str.match(regexp) ); // H,i,你,好,1,2
当然,我们可以编辑此模式:添加或删除 Unicode 属性。Unicode 属性在文章 Unicode: flag "u" and class \p{...} 中有更详细的介绍。
IE 中未实现 Unicode 属性 p{…}。如果我们确实需要它们,可以使用库 XRegExp。
或者只使用我们感兴趣的语言中的字符范围,例如 [а-я] 用于西里尔字母。
排除范围
除了正常的范围之外,还有“排除”范围,它们看起来像 [^…]。
它们由开头处的插入符号字符 ^ 表示,匹配除给定字符之外的任何字符。
例如
[^aeyo]– 除'a'、'e'、'y'或'o'之外的任何字符。[^0-9]– 除数字之外的任何字符,与\D相同。[^\s]– 任何非空格字符,与\S相同。
下面的示例查找除字母、数字和空格之外的任何字符
alert( "alice15@gmail.com".match(/[^\d\sA-Z]/gi) ); // @ and .
在 […] 中转义
通常,当我们想要找到一个特殊的字符时,我们需要对其进行转义,例如 \.。如果我们需要反斜杠,那么我们使用 \\,等等。
在方括号中,我们可以使用绝大多数特殊字符而无需转义
- 符号
. + ( )从不需要转义。 - 连字符
-在开头或结尾处不转义(它不定义范围的地方)。 - 插入符号
^仅在开头处转义(它表示排除的地方)。 - 右方括号
]始终转义(如果我们需要查找该符号)。
换句话说,所有特殊字符都允许不转义,除非它们对方括号有特殊含义。
方括号内的点 . 仅表示一个点。模式 [.,] 将查找以下字符之一:点或逗号。
在下面的示例中,正则表达式 [-().^+] 查找以下字符之一:-().^+
// No need to escape
let regexp = /[-().^+]/g;
alert( "1 + 2 - 3".match(regexp) ); // Matches +, -
…但是,如果您决定“以防万一”对其进行转义,那么不会有任何问题
// Escaped everything
let regexp = /[\-\(\)\.\^\+]/g;
alert( "1 + 2 - 3".match(regexp) ); // also works: +, -
范围和标志“u”
如果集合中存在代理对,则需要标记 u 才能使它们正常工作。
例如,让我们在字符串 𝒳 中查找 [𝒳𝒴]。
alert( '𝒳'.match(/[𝒳𝒴]/) ); // shows a strange character, like [?]
// (the search was performed incorrectly, half-character returned)
结果不正确,因为默认情况下正则表达式“不知道”代理对。
正则表达式引擎认为 [𝒳𝒴] 不是两个字符,而是四个字符。
𝒳的左半部分(1),𝒳的右半部分(2),𝒴的左半部分(3),𝒴的右半部分(4)。
我们可以这样查看它们的代码
for(let i=0; i<'𝒳𝒴'.length; i++) {
alert('𝒳𝒴'.charCodeAt(i)); // 55349, 56499, 55349, 56500
};
因此,上面的示例找到了并显示了 𝒳 的左半部分。
如果我们添加标记 u,则行为将是正确的。
alert( '𝒳'.match(/[𝒳𝒴]/u) ); // 𝒳
在查找范围时,例如 [𝒳-𝒴],也会出现类似的情况。
如果我们忘记添加标记 u,就会出现错误。
'𝒳'.match(/[𝒳-𝒴]/); // Error: Invalid regular expression
原因是,如果没有标记 u,代理对会被视为两个字符,因此 [𝒳-𝒴] 被解释为 [<55349><56499>-<55349><56500>](每个代理对都被替换为其代码)。现在很容易看出范围 56499-55349 是无效的:它的起始代码 56499 大于结束代码 55349。这是错误的正式原因。
使用标记 u,模式可以正常工作。
// look for characters from 𝒳 to 𝒵
alert( '𝒴'.match(/[𝒳-𝒵]/u) ); // 𝒴
评论
<code>标签,对于多行代码,请使用<pre>标签,对于超过 10 行的代码,请使用沙箱(plnkr,jsbin,codepen…)