5.2 RegExp
ECMAScript 通过 RegExp 类型支持正则表达式。正则表达式使用类似 Perl 的简洁语法来创建:
let expression = /pattern/flags;
这个正则表达式的 pattern(模式)可以是任何简单或复杂的正则表达式,包括字符类、限定符、 分组、向前查找和反向引用。每个正则表达式可以带零个或多个 flags(标记),用于控制正则表达式 的行为。下面给出了表示匹配模式的标记。
g:全局模式,表示查找字符串的全部内容,而不是找到第一个匹配的内容就结束。 i:不区分大小写,表示在查找匹配时忽略 pattern 和字符串的大小写。
m:多行模式,表示查找到一行文本末尾时会继续查找。
y:粘附模式,表示只查找从 lastIndex 开始及之后的字符串。
u:Unicode 模式,启用 Unicode 匹配。
s:dotAll 模式,表示元字符.匹配任何字符(包括\n 或\r)。
使用不同模式和标记可以创建出各种正则表达式,比如:
// 匹配字符串中的所有"at"
let pattern1 = /at/g;
// 匹配第一个"bat"或"cat",忽略大小写
let pattern2 = /[bc]at/i;
// 匹配以at",结尾的三个组 忽略大小写
let pattern3 = / .at/gi;
使用 RegExp 也可以基于已有的正则表达式实例,并可选择性地修改它们的标记:
console.log(re1); // "/cat/g"
const re2 = new RegExp(re1);
console.log(re2); // "/cat/g"
const re3 = new RegExp(re1, "i");
console.log(re3); // "/cat/i"
RegExp实例属性
每个 RegExp 实例都有下列属性,提供有关模式的各方面信息。
global:布尔值,表示是否设置了 g 标记。
ignoreCase:布尔值,表示是否设置了 i 标记。
unicode:布尔值,表示是否设置了 u 标记。
sticky:布尔值,表示是否设置了 y 标记。
lastIndex:整数,表示在源字符串中下一次搜索的开始位置,始终从 0 开始。
multiline:布尔值,表示是否设置了 m 标记。
dotAll:布尔值,表示是否设置了 s 标记。
source:正则表达式的字面量字符串(不是传给构造函数的模式字符串),没有开头和结尾的
斜杠。
flags:正则表达式的标记字符串。始终以字面量而非传入构造函数的字符串模式形式返回(没
有前后斜杠)。 通过这些属性可以全面了解正则表达式的信息,不过实际开发中用得并不多,因为模式声明中包含
这些信息。下面是一个例子:
let pattern1 = /\[bc\]at/i;
console.log(pattern1.global);
console.log(pattern1.ignoreCase);
console.log(pattern1.multiline);
console.log(pattern1.lastIndex);
console.log(pattern1.source);
console.log(pattern1.flags);
// false
// true 7
// false
//0
// "\[bc\]at"
// "i"
let pattern2 = new RegExp("\\[bc\\]at", "i");
console.log(pattern2.global); // false
console.log(pattern2.ignoreCase); // true
console.log(pattern2.multiline);
console.log(pattern2.lastIndex);
console.log(pattern2.source);
console.log(pattern2.flags);
// false
//0
// "\[bc\]at" // "i"
注意,虽然第一个模式是通过字面量创建的,第二个模式是通过 RegExp 构造函数创建的,但两个 模式的 source 和 flags 属性是相同的。source 和 flags 属性返回的是规范化之后可以在字面量中 使用的形式。
RegExp实例方法
RegExp 实例的主要方法是 exec()
元字符在正则表达式中都有一种或多种特殊功能,所以要匹配上面这些字符本身,就必须使用反斜 杠来转义。下面是几个例子:
// 匹配第一个"bat"或"cat",忽略大小写 let pattern1 = /[bc]at/i;
// 匹配第一个"[bc]at",忽略大小写 let pattern2 = /\[bc\]at/i;
// 匹配所有以"at"结尾的三字符组合,忽略大小写 let pattern3 = /.at/gi;
// 匹配所有".at",忽略大小写 let pattern4 = /\.at/gi;
这里的 pattern1 匹配"bat"或"cat",不区分大小写。要直接匹配"[bc]at",左右中括号都必 须像 pattern2 中那样使用反斜杠转义。在 pattern3 中,点号表示"at"前面的任意字符都可以匹配。 如果想匹配".at",那么要像 pattern4 中那样对点号进行转义。
前面例子中的正则表达式都是使用字面量形式定义的。正则表达式也可以使用 RegExp 构造函数来 创建,它接收两个参数:模式字符串和(可选的)标记字符串。任何使用字面量定义的正则表达式也可 以通过构造函数来创建,比如:
// 匹配第一个"bat"或"cat",忽略大小写 let pattern1 = /[bc]at/i;
// 跟 pattern1 一样,只不过是用构造函数创建的 let pattern2 = new RegExp("[bc]at", "i");
let text = "mom and dad and baby";
let pattern = /mom( and dad( and baby)?)?/gi;
let matches = pattern.exec(text);
console.log(matches.index);
console.log(matches.input);
console.log(matches[0]);
console.log(matches[1]);
console.log(matches[2]);
//0
// "mom and dad and baby" // "mom and dad and baby" // " and dad and baby"
// " and baby"
在这个例子中,模式包含两个捕获组:最内部的匹配项" and baby",以及外部的匹配项" and dad" 或" and dad and baby"。调用 exec()后找到了一个匹配项。因为整个字符串匹配模式,所以 matchs 数组的 index 属性就是 0。数组的第一个元素是匹配的整个字符串,第二个元素是匹配第一个捕获组的 字符串,第三个元素是匹配第二个捕获组的字符串。
如果模式设置了全局标记,则每次调用 exec()方法会返回一个匹配的信息。如果没有设置全局标 记,则无论对同一个字符串调用多少次 exec(),也只会返回第一个匹配的信息。
let text = "cat, bat, sat, fat";
let pattern = /.at/;
let matches = pattern.exec(text); console.log(matches.index); //0 console.log(matches[0]); // cat console.log(pattern.lastIndex); // 0
matches = pattern.exec(text); console.log(matches.index); //0 console.log(matches[0]); // cat console.log(pattern.lastIndex); // 0
上面例子中的模式没有设置全局标记,因此调用 exec()只返回第一个匹配项(“cat”)。lastIndex 在非全局模式下始终不变。
如果在这个模式上设置了 g 标记,则每次调用 exec()都会在字符串中向前搜索下一个匹配项,如 下面的例子所示:
let text = "cat, bat, sat, fat";
let pattern = /.at/g;
let matches = pattern.exec(text);
console.log(matches.index);
console.log(matches[0]);
console.log(pattern.lastIndex); // 3
matches = pattern.exec(text); console.log(matches.index); //5 console.log(matches[0]); // bat console.log(pattern.lastIndex); // 8
matches = pattern.exec(text);
console.log(matches.index); // 10
console.log(matches[0]); // sat
console.log(pattern.lastIndex); // 13
这次模式设置了全局标记,因此每次调用 exec()都会返回字符串中的下一个匹配项,直到搜索到 字符串末尾。注意模式的 lastIndex 属性每次都会变化。在全局匹配模式下,每次调用 exec()都会 更新 lastIndex 值,以反映上次匹配的最后一个字符的索引。
无论正则表达式是怎么创建的,继承的方法 toLocaleString()和 toString()都返回正则表达 式的字面量表示。比如:
let pattern = new RegExp("\\[bc\\]at", "gi");
console.log(pattern.toString()); // /\[bc\]at/gi
console.log(pattern.toLocaleString()); // /\[bc\]at/gi
这里的模式是通过 RegExp 构造函数创建的,但 toLocaleString()和 toString()返回的都是其 字面量的形式。
注意 正则表达式的valueOf()方法返回正则表达式本身。
RegExp 构造函数的属性。
全名简写 说明
input $_ lastMatch $& lastParen $+ leftContext $` rightContext $’
最后搜索的字符串(非标准特性) 最后匹配的文本 最后匹配的捕获组(非标准特性)
input 字符串中出现在 lastMatch 前面的文本 input 字符串中出现在 lastMatch 后面的文本
通过这些属性可以提取出与 exec()和 test()执行的操作相关的信息。来看下面的例子:
let text = "this has been a short summer";
let pattern = /(.)hort/g;
if (pattern.test(text)) {
console.log(RegExp.input); // this has been a short summer
console.log(RegExp.leftContext); // this has been a
console.log(RegExp.rightContext); // summer
console.log(RegExp.lastMatch); // short
console.log(RegExp.lastParen); // s
}
以上代码创建了一个模式,用于搜索任何后跟"hort"的字符,并把第一个字符放在了捕获组中。 不同属性包含的内容如下。
input 属性中包含原始的字符串。
leftConext 属性包含原始字符串中"short"之前的内容,rightContext 属性包含"short"
之后的内容。
lastMatch 属性包含匹配整个正则表达式的上一个字符串,即"short"。
lastParen 属性包含捕获组的上一次匹配,即"s"。 这些属性名也可以替换成简写形式,只不过要使用中括号语法来访问,如下面的例子所示,因为大
多数简写形式都不是合法的 ECMAScript 标识符:
let pattern = /(.)hort/g;
/*
* 注意:Opera 不支持简写属性名 * IE 不支持多行匹配
*/
if (pattern.test(text)) {
console.log(RegExp.$_);
console.log(RegExp["$`"]);
console.log(RegExp["$'"]);
console.log(RegExp["$&"]);
console.log(RegExp["$+"]);
// this has been a short summer
// this has been a
// summer
// short
//s
}
RegExp 还有其他几个构造函数属性,可以