RegExp

基线 广泛可用

此功能非常成熟,可在许多设备和浏览器版本中运行。它已在浏览器中可用,自 2015 年 7 月.

**RegExp** 对象用于匹配文本与模式。

有关正则表达式的介绍,请阅读 JavaScript 指南中的正则表达式章节。有关正则表达式语法的详细信息,请阅读正则表达式参考

描述

字面量表示法和构造函数

有两种方法可以创建 RegExp 对象:字面量表示法构造函数

  • 字面量表示法 在两个斜杠之间采用一个模式,后面跟着可选的 标志,在第二个斜杠之后。
  • 构造函数 将字符串或 RegExp 对象作为第一个参数,以及一个可选的 标志 字符串作为第二个参数。

以下三个表达式创建了相同的正则表达式对象

js
const re = /ab+c/i; // literal notation
// OR
const re = new RegExp("ab+c", "i"); // constructor with string pattern as first argument
// OR
const re = new RegExp(/ab+c/, "i"); // constructor with regular expression literal as first argument

在使用正则表达式之前,必须先对其进行编译。此过程允许它们更有效地执行匹配。有关此过程的更多信息,请参阅dotnet 文档

字面量表示法在表达式被求值时会导致正则表达式被编译。另一方面,RegExp 对象的构造函数 new RegExp('ab+c') 会导致在运行时编译正则表达式。

当你想从动态输入构建正则表达式时,请使用字符串作为 RegExp() 构造函数的第一个参数。

构造函数中的标志

表达式 new RegExp(/ab+c/, flags) 将使用第一个参数的源和第二个参数提供的 标志 创建一个新的 RegExp

使用构造函数时,需要使用正常的字符串转义规则(在字符串中包含特殊字符时,在前面加上 \)。

例如,以下内容是等效的

js
const re = /\w+/;
// OR
const re = new RegExp("\\w+");

对正则表达式的特殊处理

注意: 某些东西是否是“正则表达式”可以鸭子类型。它不必是 RegExp

某些内置方法会对正则表达式进行特殊处理。它们通过多个步骤 来决定 x 是否为正则表达式。

  1. x 必须是一个对象(而不是一个原始值)。
  2. 如果x[Symbol.match] 不是 undefined,请检查它是否为真值
  3. 否则,如果 x[Symbol.match]undefined,请检查 x 是否是用 RegExp 构造函数创建的。(此步骤应该很少发生,因为如果 x 是一个 RegExp 对象,并且没有被篡改过,它应该有一个 Symbol.match 属性。)

请注意,在大多数情况下,它会通过 Symbol.match 检查,这意味着

  • 一个实际的 RegExp 对象,其 Symbol.match 属性的值为假值,但不为 undefined(即使其他一切正常,例如 exec[Symbol.replace]()),可以像不是正则表达式一样使用。
  • 具有 Symbol.match 属性的非 RegExp 对象将被视为正则表达式。

做出这种选择的原因是 [Symbol.match]() 是最能表明某个东西意图用于匹配的属性。(exec 也可以使用,但因为它不是符号属性,所以会有太多误报。)处理正则表达式特殊情况的地方包括

例如,String.prototype.endsWith() 会将所有输入强制转换为字符串,但如果参数是正则表达式,则会抛出异常,因为它只设计用于匹配字符串,并且使用正则表达式很可能是开发人员的错误。

js
"foobar".endsWith({ toString: () => "bar" }); // true
"foobar".endsWith(/bar/); // TypeError: First argument to String.prototype.endsWith must not be a regular expression

你可以通过将 [Symbol.match] 设置为一个假值(不为 undefined)来绕过检查。这意味着正则表达式不能用于 String.prototype.match()(因为没有 [Symbol.match]match() 会使用 re.toString() 添加的两个包围斜杠来构建一个新的 RegExp 对象),但它可以用于几乎所有其他情况。

js
const re = /bar/g;
re[Symbol.match] = false;
"/bar/g".endsWith(re); // true
re.exec("bar"); // [ 'bar', index: 0, input: 'bar', groups: undefined ]
"bar & bar".replace(re, "foo"); // 'foo & foo'

Perl 风格的 RegExp 属性

请注意,一些RegExp属性同时拥有长名称和短名称(类似 Perl)。这两个名称始终指向相同的值。(JavaScript 的正则表达式是模仿 Perl 语言中的正则表达式。)另请参阅 已弃用的RegExp 属性

构造函数

RegExp()

创建一个新的RegExp 对象。

静态属性

RegExp.$1, …, RegExp.$9 已弃用

包含括号内子字符串匹配的静态只读属性。

RegExp.input ($_) 已弃用

包含最后一次成功匹配正则表达式的字符串的静态属性。

RegExp.lastMatch ($&) 已弃用

包含最后一次匹配子字符串的静态只读属性。

RegExp.lastParen ($+) 已弃用

包含最后一次括号内子字符串匹配的静态只读属性。

RegExp.leftContext ($`) 已弃用

包含最近匹配之前子字符串的静态只读属性。

RegExp.rightContext ($') 已弃用

包含最近匹配之后子字符串的静态只读属性。

RegExp[Symbol.species]

用于创建派生对象的构造函数。

实例属性

这些属性定义在RegExp.prototype 上,由所有RegExp 实例共享。

RegExp.prototype.constructor

创建实例对象的构造函数。对于RegExp 实例,初始值为 RegExp 构造函数。

RegExp.prototype.dotAll

. 是否匹配换行符。

RegExp.prototype.flags

包含RegExp 对象标志的字符串。

RegExp.prototype.global

是否将正则表达式测试应用于字符串中的所有可能的匹配,还是仅针对第一个匹配。

RegExp.prototype.hasIndices

正则表达式结果是否公开捕获子字符串的开始和结束索引。

RegExp.prototype.ignoreCase

在尝试匹配字符串时是否忽略大小写。

RegExp.prototype.multiline

是否跨多行搜索字符串。

RegExp.prototype.source

模式文本。

RegExp.prototype.sticky

搜索是否粘性。

RegExp.prototype.unicode

Unicode 功能是否已启用。

RegExp.prototype.unicodeSets

v 标志(u 模式升级版)是否已启用。

这些属性是每个RegExp 实例的自身属性。

lastIndex

开始下一次匹配的索引。

实例方法

RegExp.prototype.compile() 已弃用

在脚本执行期间(重新)编译正则表达式。

RegExp.prototype.exec()

在其字符串参数中执行匹配搜索。

RegExp.prototype.test()

在其字符串参数中测试匹配。

RegExp.prototype.toString()

返回表示指定对象的字符串。覆盖 Object.prototype.toString() 方法。

RegExp.prototype[Symbol.match]()

对给定字符串执行匹配并返回匹配结果。

RegExp.prototype[Symbol.matchAll]()

返回正则表达式对字符串的所有匹配。

RegExp.prototype[Symbol.replace]()

使用新子字符串替换给定字符串中的匹配项。

RegExp.prototype[Symbol.search]()

在给定字符串中搜索匹配项并返回模式在字符串中找到的索引。

RegExp.prototype[Symbol.split]()

通过将字符串分割成子字符串,将给定字符串分割成数组。

示例

使用正则表达式更改数据格式

以下脚本使用 String.prototype.replace() 方法匹配格式为first last 的名称,并将其输出为格式为last, first 的名称。

在替换文本中,脚本使用$1$2 来表示正则表达式模式中相应匹配括号的结果。

js
const re = /(\w+)\s(\w+)/;
const str = "Maria Cruz";
const newstr = str.replace(re, "$2, $1");
console.log(newstr);

这将显示"Cruz, Maria"

使用正则表达式分割具有不同行结束符/行尾/换行的行

默认行结束符因平台而异(Unix、Windows 等)。此示例中提供的行分割适用于所有平台。

js
const text = "Some text\nAnd some more\r\nAnd yet\rThis is the end";
const lines = text.split(/\r\n|\r|\n/);
console.log(lines); // [ 'Some text', 'And some more', 'And yet', 'This is the end' ]

请注意,正则表达式中模式的顺序很重要。

在多行上使用正则表达式

js
const s = "Please yes\nmake my day!";

s.match(/yes.*day/);
// Returns null

s.match(/yes[^]*day/);
// Returns ["yes\nmake my day"]

使用带粘性标志的正则表达式

sticky 标志指示正则表达式在目标字符串中执行粘性匹配,尝试从 RegExp.prototype.lastIndex 开始匹配。

js
const str = "#foo#";
const regex = /foo/y;

regex.lastIndex = 1;
regex.test(str); // true
regex.lastIndex = 5;
regex.test(str); // false (lastIndex is taken into account with sticky flag)
regex.lastIndex; // 0 (reset after match failure)

粘性标志与全局标志的区别

使用粘性标志y,下一次匹配必须发生在lastIndex 位置,而使用全局标志g,匹配可以发生在lastIndex 位置或更晚。

js
const re = /\d/y;
let r;
while ((r = re.exec("123 456"))) {
  console.log(r, "AND re.lastIndex", re.lastIndex);
}

// [ '1', index: 0, input: '123 456', groups: undefined ] AND re.lastIndex 1
// [ '2', index: 1, input: '123 456', groups: undefined ] AND re.lastIndex 2
// [ '3', index: 2, input: '123 456', groups: undefined ] AND re.lastIndex 3
//  … and no more match.

使用全局标志g,将匹配所有 6 位数字,而不仅仅是 3 位。

正则表达式和 Unicode 字符

\w\W 仅匹配基于 ASCII 的字符;例如,azAZ09 以及_

要匹配来自其他语言(如西里尔字母或希伯来语)的字符,请使用\uhhhh,其中hhhh 是字符的十六进制 Unicode 值。

此示例演示如何从单词中分离出 Unicode 字符。

js
const text = "Образец text на русском языке";
const regex = /[\u0400-\u04FF]+/g;

const match = regex.exec(text);
console.log(match[0]); // 'Образец'
console.log(regex.lastIndex); // 7

const match2 = regex.exec(text);
console.log(match2[0]); // 'на' (did not log 'text')
console.log(regex.lastIndex); // 15

// and so on

Unicode 属性转义 功能提供了一种更简单的方法来定位特定的 Unicode 范围,允许使用\p{scx=Cyrl}(匹配任何西里尔字母)或\p{L}/u(匹配任何语言的字母)之类的语句。

从 URL 中提取子域名

js
const url = "http://xxx.domain.com";
console.log(/^https?:\/\/(.+?)\./.exec(url)[1]); // 'xxx'

注意:通常,最好使用浏览器的内置 URL 解析器(使用 URL API)来解析 URL,而不是使用正则表达式。

从动态输入构建正则表达式

js
const breakfasts = ["bacon", "eggs", "oatmeal", "toast", "cereal"];
const order = "Let me get some bacon and eggs, please";

order.match(new RegExp(`\\b(${breakfasts.join("|")})\\b`, "g"));
// Returns ['bacon', 'eggs']

规范

规范
ECMAScript 语言规范
# sec-regexp-regular-expression-objects

浏览器兼容性

BCD 表格仅在启用 JavaScript 的浏览器中加载。

Firefox 特定说明

从 Firefox 34 开始,对于带有量词的捕获组,如果量词阻止其执行,则捕获组的匹配文本现在为undefined,而不是空字符串。

js
// Firefox 33 or older
"x".replace(/x(.)?/g, (m, group) => {
  console.log(`group: ${JSON.stringify(group)}`);
});
// group: ""

// Firefox 34 or newer
"x".replace(/x(.)?/g, (m, group) => {
  console.log(`group: ${group}`);
});
// group: undefined

请注意,由于 Web 兼容性,RegExp.$N 仍将返回空字符串而不是undefined (bug 1053944).

另请参阅