RegExp
描述
字面量表示法和构造函数
有两种方法可以创建 RegExp
对象:字面量表示法 和 构造函数。
以下三个表达式创建了相同的正则表达式对象
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
。
使用构造函数时,需要使用正常的字符串转义规则(在字符串中包含特殊字符时,在前面加上 \
)。
例如,以下内容是等效的
const re = /\w+/;
// OR
const re = new RegExp("\\w+");
对正则表达式的特殊处理
注意: 某些东西是否是“正则表达式”可以鸭子类型。它不必是 RegExp
!
某些内置方法会对正则表达式进行特殊处理。它们通过多个步骤 来决定 x
是否为正则表达式。
x
必须是一个对象(而不是一个原始值)。- 如果
x[Symbol.match]
不是undefined
,请检查它是否为真值。 - 否则,如果
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()
、startsWith()
和includes()
如果第一个参数是正则表达式,则会抛出TypeError
。String.prototype.matchAll()
和replaceAll()
在调用其[Symbol.matchAll]()
或[Symbol.replace]()
方法之前,会检查第一个参数是否是正则表达式,以及是否设置了 全局 标志。RegExp()
构造函数只在pattern
是正则表达式(以及其他几个条件)的情况下,直接返回pattern
参数。如果pattern
是正则表达式,它也会查询pattern
的source
和flags
属性,而不是将pattern
强制转换为字符串。
例如,String.prototype.endsWith()
会将所有输入强制转换为字符串,但如果参数是正则表达式,则会抛出异常,因为它只设计用于匹配字符串,并且使用正则表达式很可能是开发人员的错误。
"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
对象),但它可以用于几乎所有其他情况。
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
来表示正则表达式模式中相应匹配括号的结果。
const re = /(\w+)\s(\w+)/;
const str = "Maria Cruz";
const newstr = str.replace(re, "$2, $1");
console.log(newstr);
这将显示"Cruz, Maria"
。
使用正则表达式分割具有不同行结束符/行尾/换行的行
默认行结束符因平台而异(Unix、Windows 等)。此示例中提供的行分割适用于所有平台。
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' ]
请注意,正则表达式中模式的顺序很重要。
在多行上使用正则表达式
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
开始匹配。
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
位置或更晚。
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 的字符;例如,a
到z
,A
到Z
,0
到9
以及_
。
要匹配来自其他语言(如西里尔字母或希伯来语)的字符,请使用\uhhhh
,其中hhhh
是字符的十六进制 Unicode 值。
此示例演示如何从单词中分离出 Unicode 字符。
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 中提取子域名
const url = "http://xxx.domain.com";
console.log(/^https?:\/\/(.+?)\./.exec(url)[1]); // 'xxx'
注意:通常,最好使用浏览器的内置 URL 解析器(使用 URL API)来解析 URL,而不是使用正则表达式。
从动态输入构建正则表达式
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
,而不是空字符串。
// 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).