正则表达式的标志(flags)在字面量中以字母形式出现在正则表达式字面量的末尾,也就是双反斜杠之后的位置,使用RegExp构造函数创建时也可以通过传入第二参数进行指定。它们的作用是用于修改正则表达式的默认行为。
"g"(全局匹配)、"i"(不区分大小写匹配)、"m"(多行匹配)、"s"("."元字符匹配换行符)、"u"(Unicdoe匹配)、"y"(粘性匹配)、"d"(提供捕获组更多信息),这些标志可以单独使用,也可以组合使用,以满足特定的匹配需求。
"g"标志
"g"标志是表示使用全局匹配模式。默认情况下正则表达式将会在匹配到第一个匹配项后便会结束匹配,而使用"g"标志则正则表达式会在整个字符串中进行匹配所有的符合项。但具体的,"g"标志在不同方法的方法下存在不同的行为。
exec方法:
const regex = /abc,/;
const text = 'abc,abc,abc,';
console.log(regex.exec(text));
// [ 'abc,', index: 0, input: 'abc,abc,abc,', groups: undefined ]
console.log(regex.exec(text));
// [ 'abc,', index: 0, input: 'abc,abc,abc,', groups: undefined ]
match方法:
const regex = /abc,/;
const text = 'abc,abc,abc,';
console.log(text.match(regex));
// [ 'abc,', index: 0, input: 'abc,abc,abc,', groups: undefined ]
console.log(text.match(regex));
// [ 'abc,', index: 0, input: 'abc,abc,abc,', groups: undefined ]
可以看出来在未使用"g"标志时两者的返回值一致,且都只匹配了第一组"abc,"。
"g"标志下的exec方法:
const regex = /abc,/g;
const text = 'abc,abc,abc,';
console.log(regex.exec(text));
// [ 'abc,', index: 0, input: 'abc,abc,abc,', groups: undefined ]
console.log(regex.exec(text));
// [ 'abc,', index: 4, input: 'abc,abc,abc,', groups: undefined ]
console.log(regex.exec(text));
// [ 'abc,', index: 8, input: 'abc,abc,abc,', groups: undefined ]
console.log(regex.exec(text));
// null
console.log(regex.exec(text));
// [ 'abc,', index: 0, input: 'abc,abc,abc,', groups: undefined ]
在使用"g"标志的正则表达式下,exec的行为发生了改变。如果匹配成功返回一个数组,下次匹配将会接着这个位置向后匹配。如果无匹配内容则返回"null",下次匹配从起始位置开始。注意返回值数组中的index,它表示这次匹配的起始位置。
"g"标志下的match方法:
const regex = /abc,/g;
const text = 'abc,abc,abc,';
console.log(text.match(regex));
// [ 'abc,', 'abc,', 'abc,' ]
console.log(text.match(regex));
// [ 'abc,', 'abc,', 'abc,' ]
match方法将会返回一个数组,每一项值表示匹配成功的内容,也就是说"g"标志的match方法会一次性匹配字符串中所有的内容。
还有一点需要注意的是,使用全局模式匹配时,exec方法可以通过设置正则表达式的lastIndex属性来设置下一次匹配的起始位置。
const regex = /abc,/g;
const text = 'abc,abc,abc,';
regex.lastIndex = 4; // 从第3个字符后开始匹配
console.log(regex.exec(text));
// [ 'abc,', index: 4, input: 'abc,abc,abc,', groups: undefined ]
"y"标志
"y"标志表示正则表达式执行的是粘性(sticky)匹配。粘性匹配是指从目标字符串的指定位置开始匹配,而不是在整个字符串中起始位置开始查找匹配,这可以实现在更精确的位置上进行匹配。
const regex = /abc,/y;
const str = 'abc,abc,abc,';
regex.lastIndex = 4; // 从第3个字符后开始匹配
console.log(regex.exec(str)); // 匹配到第2组 "abc"
console.log(regex.exec(str)); // 匹配到第3组 "abc"
console.log(regex.exec(str)); // null
console.log(regex.exec(str)); // 回到起始位置,匹配第一组 "abc"
如果在指定位置匹配为null,将会重置lastIndex为0,从开头重新进行匹配。
const regex = /abc,/y;
const str = 'abc,abc,abc,';
regex.lastIndex = 2; // 从第2个字符后开始匹配
console.log(regex.exec(str)); // null 这个位置不匹配,回到起始位置开始匹配
console.log(regex.exec(str)); // 匹配到第1组 "abc"
console.log(regex.exec(str)); // 匹配到第2组 "abc"
console.log(regex.exec(str)); // 匹配到第3组 "abc"
如果"g"标志(全局匹配)与"y"标志下一起使用,在不同的方法中使用会有不同的结果。在正则表达式上的exec方法上同时使用时将会忽略"g"标志,而在字符串方法中使用match方法时将会忽略"y"标志。
与"g"标志的正则表达式相比,"y"标志的正则表达式匹配时只会从当前位置开始执行匹配,而不会像"g"标志那样尽可能地向后匹配。换句话说,"y" 标志的正则表达,下一次匹配一定在 lastIndex
位置开始,而 "g" 标志的正则表达式,下一次匹配可能在 lastIndex
位置开始,也可能在这个位置的后面开始。
"i"标志
"i"标志表示正则表达式在匹配时忽略字母大小写差异。
const regex = /hello/;
const regex_i = /hello/i;
const text = 'Hello world!';
console.log(regex.test(text)); // false,区分大小写匹配
console.log(regex_i.test(text)); // true,不区分大小写匹配
"m"标志
"m"标志是表示正则表达式启用多行匹配模式,以方便进行多行文本处理。
"m"标志主要是会影响 "^" 和 "$" 元字符的行为。在默认情况下,"^" 匹配字符串的开头,而 "$"
匹配字符串的末尾。但使用 "m" 标志后,它们分别匹配每一行的开头和末尾。
const text = '1.亲手折断的玫瑰。\n2.又问为何枯萎。';
const regexp = /..$/gi;
console.log(text.match(regexp));
// [ '萎。' ]
const regexp_m = /..$/gim;
console.log(text.match(regexp_m));
// [ '瑰。', '萎。' ]
})();
在上述示例的代码中,如果不执行多行匹配模式,将只匹配字符串结束处的句号。使用多行模式则会匹配每行结束前的句号。
"s"标志
使用"s"标志将会允许"."元字符能够匹配包括行终止符在内的所有字符。默认情况下,正则表达式中的 "."
元字符匹配除行终止符之外的任何字符。
行终止符包括:
- U+000A 换行符("
\n
") - U+000D 回车符("
\r
") - U+2028 行分隔符
- U+2029 段分隔符
const text = ['\r', '\n', '\u2028', '\u2029'];
const regexp = /./;
const regexp_s = /./s;
text.forEach((item) => console.log(regexp.test(item)));
// false false false false
text.forEach((item) => console.log(regexp_s.test(item)));
// true true true true
const text = '你说的黑是什么黑\n你说的白是什么白';
const reg_1 = /.+/;
console.log(reg_1.exec(text)[0]);
// 你说的黑是什么黑
const reg_2 = /.+/s;
console.log(reg_2.exec(text)[0]);
// 你说的黑是什么黑
// 你说的白是什么白
在上面的这个示例中,第一个正则表达式匹配到换行符("\n")就停止了。而第二个正则表达式则进行了完整匹配,输出打印了两行字符串。
若要使“.”与 astral 字符(大于 \uFFFF 的 Unicode 字符)匹配,额外使用"u"标志(即"/./su
"),".
"将会匹配所有的 Unicode 字符。(关于什么是 Unicode 编码可以查看这篇文章)
"u"标志
"u"标志表示正则表示启用Unicode匹配模式,允许正则表达式中出现Unicode码点,这将可以实现非常简单的处理各种 Unicode 字符,特别是一些特殊的Unicode字符和码点。
比如说"u"标志可以使用Unicode十六进制码点匹配其对应的字符。比如:/\u{68A6}/u
,这个正则表达式可以实现对中文字符"梦"的匹配,因为这个字符对应的Unicode码点就是U+68A6。
const word = '梦';
const reg = /\u{68A6}/g;
const reg_u = /\u{68A6}/gu;
console.log(reg.test(word));
// false
console.log(reg_u.test(word));
// true
但是请注意,如果是使用无花括号的形式,例如:/\u68A6/g
。此时有无"u"标志都将会匹配。
const word = '梦';
const reg = /\u68A6/g;
const reg_unicode = /\u68A6/gu;
console.log(reg.test(word));
// true
console.log(reg_unicode.test(word));
// true
"u"标志也使得正则表达式中得"\p"字符类生效,例如 \p{}
和 \P{}
。
const text = '你说的黑是什么黑,abCDEFg';
const reg_1 = /\p{Script=Han}+/gu;
// 匹配汉字字符
const reg_2 = /\p{Lu}+/gu;
// 匹配大写字母
console.log(text.match(reg_1), text.match(reg_2));
// [ '你说的黑是什么黑' ] [ 'CDEF' ]
了解更多关于"\p
"可以看这个内容。
"d"标志
"d"标志表示正则表达式匹配的结果应该包含匹配内容和捕获组的开始和结束的索引。该标志不会存在任何副作用,它只是在匹配结果中提供额外的信息。它是在ECMAScript 2022标准中加入。
在使用"d"标志的正则表达式使用exec()方法去执行匹配时,返回的数组中将会增加一个indices属性,它的值也是一个数组。它的每项都是包含两个数值的数组,分别表示匹配内容的起始和结束位置。第一项是整个正则表达式所匹配的内容位于字符串中的位置,之后的每项则是小括号捕获组捕获的内容位于字符串中的位置,groups则是具名捕获组捕获的内容位置。
const regexp = /(\d{2}).(\d{2})/dg;
const text = '北京时间今天上午11时14分,中国成功发射了神舟十七号载人航天飞船。';
console.log(regexp.hasIndices);
// true
console.log(regexp.exec(text));
// [
// '11时14',
// '11',
// '14',
// index: 8,
// input: '北京时间今天上午11时14分,中国成功发射了神舟十七号载人航天飞船。',
// groups: undefined,
// indices: [ [ 8, 13 ], [ 8, 10 ], [ 11, 13 ], groups: undefined ]
// ]
文章评论