JavaScript 正则表达式
1. 概述
正则表达式用于描述各种复杂的字符串关系,使用正则表达式能够更加灵活便捷地处理字符串,它是使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式。
2. 字符串规则描述符
2.1 定位符:描述字符的边界
符号 | 描述 | 说明 |
^ | 匹配一个字符串的起始字符 | 如果多行标志被设置为 true,那么也匹配换行符后紧跟的位置。 |
$ | 匹配一个字符串的结尾字符 | 如果多行标志被设置为 true,那么也匹配换行符前的位置。 |
\b | 匹配一个单词的边界 | - |
\B | 匹配非 单词边界 |
相当于\b 匹配的反集 |
2.2 限定符:描述重复匹配的次数
符号 | 描述 | 说明 |
? | 匹配该限定符前的字符0 或1 次 |
等价于 {0,1} ,如 colou?r 可以匹配colour 和color |
+ | 匹配该限定符前的字符1 或多 次 |
等价于 {1,} ,如 hel+o 可以匹配helo 、hello 、helllo 、… |
* | 匹配该限定符前的字符0 或多 次 |
等价于 {0,} ,如 hel*o 可以匹配heo 、helo 、hello 、helllo 、… |
{n} | 匹配该限定符前的字符n 次 |
如 hel{2}o 只可以匹配hello |
{n,} | 匹配该限定符前的字符最少n次 |
如 hel{2,}o 可以匹配hello 、helllo 、… |
{n,m} | 匹配该限定符前的字符最少n次 ,最多m次 |
如 hel{2,3}o 只可以匹配hello 和 helllo |
【例】写出从字符串string
的任意一行中匹配颜色名
和颜色值
的正则表达式:
// 待提取的字符串 var str = `$navajowhite: #FFDEAD !default; $moccasin: #FFE4B5 !default; $bisque: #FFE4C4 !default; $mistyrose: #FFE4E1 !default; $blanchedalmond: #FFEBCD !default; $lavenderblush: #FFF0F5 !default;`
目标 | 表达式 | 说明 |
提取颜色名 | '/\w{1,15}/ |
考虑到上面颜色名单词最长没有超过15个字符串,最短肯定得有字符,所以写了{1,15} ,但也可以是其它的合理值即可。 |
提取颜色值 | '/#.{6}/', |
颜色值由# 符号开头,一共由六位十六进制数字,十六进制数字为是个阿拉伯数字字符加A、B、C、D、E、F五个英文字符构成。 |
2.3 字符描述
符号 | 描述 | 说明 |
\d | 匹配任意数字 | |
\s | 匹配任意空白符 | |
\w | 匹配任意字母、数字、下划线、汉字等 | |
\D | 匹配任意非 数字 |
|
\S | 匹配任意非 空白符 |
|
\W | 匹配除了 字母、数字、下划线、汉字以外的字符 |
|
. | 匹配除了换行符 以外的任意字符 |
形式 | 描述 | 说明 |
[A-Z] | 区间匹配,匹配字母表该区间所有大写字母 | 如[C-F] 匹配字符C、D、E、F |
[a-z] | 区间匹配,匹配字母表该区间所有小写字母 | 如[c-f] 匹配字符c、d、e、f |
[0-9] | 区间匹配,匹配该区间内的所有数字 | 如[3-6] 匹配字符3、4、5、6 |
[ABCD] | 列表匹配,匹配[] 中列出的所有字母 |
如这里列出的A、B、C、D都会被匹配 |
[^ABCD] | 列表排除,匹配除了[] 中列出的字符外的所有字符 |
如这里列出的A、B、C、D都会被排除而匹配其它字符 |
例如,匹配IPV4地址:
var url = 'https://127.0.0.1:8888/Home/Welcome'; var re = /[1-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[1-9]{1,3}/; var res = re[Symbol.matchAll](url); console.log(Array.from(res, x => x[0])[0])
Out[1]:
127.0.0.1
2.4 管道符:“或”匹配逻辑
管道符就是一根竖线:|
,再正则表达式中标识”或“。由于匹配方向时从左向右进行的,假如有两个正则表达式A
和B
,那么使用 A|B
匹配字符串时,只要前一个样式完全匹配成功,那么后一个就不再匹配。
2.5 转义字符:将特殊符号标识为普通字符
在正则表达式中用于标识特殊含义的符号如.
用于标识一个任意的非换行符字符,^
标识起始字符,等等。但是我们希望匹配到这些字符本身也是经常遇到的情况,如IPV4地址使用.
作为分割符。因此我们如果需要完整提取IPV4地址就需要表示.
本身。由于直接使用点已经有了其它的含义,因此我们使用一个\
号进行转义,即使用\.
来表示点(.
)。其它在正则中有特殊含义的符号也可以使用类似的方式。
2.6 分组
与数学计算中采用小括号()
进行算式分组一样,正则模板也能够分组表达,目的是将某一部分正则模板作为一个整体表达,例如模板:
var str = '4aderf weew16a dawedb_ewwecs aswed 6aew'; var re = /(we|ew){1}/g; var res = re[Symbol.matchAll](str); console.log(Array.from(res1, x => x[0]))
Out[]:
[‘we’, ‘ew’, ‘we’, ‘ew’, ‘we’, ‘we’, ‘ew’]
这里将(we|ew)
作为一个组,{n}
对改组指定重复匹配的次数。
3 创建正则表达式对象的方法
以下三种方法创建都是可以的:
/pattern/flags
new RegExp(pattern[, flags])
RegExp(pattern[, flags])
3.1 正则对象的字面量
字面量用于表达源代码中一个固定值。在 JavaScript 中字正则面量也可以用于创建正则表达式对象,当表达式被赋值时,字面量形式提供正则表达式的编译状态,当正则表达式保持为常量时使用字面量。例如当你在循环中使用字面量构造一个正则表达式时,正则表达式不会在每一次迭代中都被重新编译(recompiled)。
3.2 通过调用RegExp
对象的构造函数创建
var re = /ab+c/;
3.3 直接写正则表达式字面量创建
var re = new RegExp("ab+c");
3.4 比较
项目 | 特定 | 场景 | 说明 |
字面量 | 当表达式被赋值时,字面量形式提供正则表达式的编译状态 | 当正则表达式保持为常量时使用字面量 | 例如当你在循环中使用字面量构造一个正则表达式时,正则表达式不会在每一次迭代中都被重新编译 |
构造函数 | 正则表达式对象的构造函数,如 new RegExp('ab+c') 提供了正则表达式运行时编译 |
如果你知道正则表达式模式将会改变,或者你事先不知道什么模式,而是从另一个来源获取,如用户输入,这些情况都可以使用构造函数 | - |
4. RegExp 对象
RegExp
对象用于将文本与一个模式匹配。
4.1 构造函数 RegExp
()
RegExp
()构造函数用于创建一个RegExp
对象,这与直接使用字面量创建的方式在多数情况下是可以通用的。
以下三个表达式创建相同的正则表达式:
/ab+c/i new RegExp(/ab+c/, 'i') // 字面量 new RegExp('ab+c', 'i') // 构造函数
参数
pattern :正则模板
正则表达式的文本。
从ES5开始,这也可以是另一个RegExp对象或文字(仅用于两个RegExp构造函数符号)。模式可以包含特殊字符special characters来匹配比字面值字符串更广泛的值范围。
flags (标志)
如果指定, flags
是包含要添加的标志的字符串。ES6开始,如果为模式提供了一个对象,flags字符串将替换该对象的任何标志(并且lastIndex将重置为0)。如果没有指定flags并且提供了一个正则表达式对象,则该对象的flags(和lastIndex
值)将被复制。flags
可包含下列任何字符的组合:
符号 | 描述 | 说明 |
g |
全局匹配 | 找到所有的匹配,而不是在第一个匹配之后停止。 |
i |
忽略大小写 | 如果u 标志也被启用,使用Unicode大小写折叠。 |
m |
多行匹配 | 将开始和结束字符(^ and $ )视为在多行上工作。换句话说,匹配每一行的开头或结尾each line (由\n 或者\r 分隔),而不仅仅是整个输入字符串的开头或结尾。 |
s |
点号匹配所有字符 | 允许. 去匹配新的行 |
u |
unicode | 将 pattern 视为 Unicode 码位序列。 参考 二进制字符串 |
y |
sticky,粘性匹配 | 仅从目标字符串中此正则表达式的 lastIndex 属性指示的索引中匹配。不尝试从任何后续索引中匹配 |
flag 不写在正则表达式里,标记位于表达式之外,格式为:
/pattern/flags
4.2 属性
4.2.1 静态属性
1. get RegExp[@@species
]
species
是一个访问器属性,它返回 RegExp 对象
的默认构造器。子类构造器可能会覆盖它,来修改构造器的指派。
原始对象中的 species
属性
species属性返回默认的构造函数,即RegExp对象的RegExp构造函数:
RegExp[Symbol.species]; // RegExp()函数
派生对象中的 species
属性
在派生的集合对象中(例如,您的自定义regexp MyRegExp),MyRegExp种类是MyRegExp构造函数。但是,您可能希望覆盖它,以便在派生类方法中返回父RegExp对象:
class MyRegExp extends RegExp { // 将 MyRegExp species 覆盖到父 RegExp 的构造函数 static get [Symbol.species]() { return RegExp; } }
例如:
class MyRegExp extends RegExp { // 将MyRegExp种类覆盖到父RegExp构造函数 static get [Symbol.species]() { return RegExp; } } const regex1 = new MyRegExp('foo', 'g'); console.log(regex1.test('football')); // 期望输出: true
2 RegExp.lastIndex
仅当正则表达式实例使用
g
标志指示全局搜索 或 使用y
标志指示粘性搜索时,才设置此属性。#知识点链接
lastIndex
是 RegExp 实例的读/写整数属性,指定开始下一个匹配的索引。lastIndex
不是
RegExp原型的属性,而是仅从 RegExp 实例中暴露出来。
对给定输入调用 test() 和 exec() 时,适用以下规则:
- 如果lastIndex 大于 输入的长度,
exec
() 或test
() 将找不到匹配,lastIndex
将被设置为0
。 - 如果lastIndex小于或等于输入的长度,
exec
()或test
()将尝试匹配从lastIndex
开始的输入。
例子
考虑以下语句序列:
var re = /(hi)?/g;
匹配空字符串:
console.log(re.exec('hi')); console.log(re.lastIndex);
返回 lastIndex
等于2的["hi", "hi"]
:
console.log(re.exec('hi')); console.log(re.lastIndex);
返回 ["", undefined]
,一个空数组,其第零个元素是匹配字符串。在本例中,空字符串是因为lastIndex
是2(现在仍然是2),hi
的长度是2。
4.2.2 实例属性
属性名 | 描述 | 说明 |
RegExp.prototype.flags | 含有 RegExp 对象 flags 的字符串 |
|
RegExp.prototype.dotAll | . 是否要匹配新行(newlines |
|
RegExp.prototype.global | 针对字符串中所有可能的匹配项测试正则表达式,还是仅针对第一个匹配项 | |
RegExp.prototype.ignoreCase | 匹配文本的时候是否忽略大小写 | |
RegExp.prototype.multiline | 是否进行多行搜索 | |
RegExp.prototype.source | 返回一个值为当前正则表达式对象的模式文本的字符串 | 该字符串不会包含正则字面量两边的斜杠以及任何的标志字符 |
RegExp.prototype.sticky | 仅从正则表达式的 lastIndex 属性表示的索引处搜索 | 只读属性 |
RegExp.prototype.unicode | Unicode 功能是否开启 | 只读属性 |
1. flags
属性
含有 RegExp
对象 flags 的字符串。
flags属性中的标志以字典序排序(从左到右,即"gimuy")。
属性描述符
RegExp.prototype.flags 属性的属性特性: |
|
writable | false |
enumerable | false |
configurable | true |
例子
/foo/ig.flags; // "gi" /bar/myu.flags; // "muy"
2. dotAll
属性
.
是否要匹配新行(newlines)。
dotAll 属性表明是否在正则表达式中一起使用"s"修饰符(引入/s修饰符,使得.可以匹配任意单个字符)。
dotAll 是一个只读的属性,属于单个正则表达式实例。
如果使用了"s"修饰符,dotAll 的值将返回Boolean类型的true,否则将返回false。“s"修饰符表示,特殊字符”."应另外匹配字符串中的下述行终结符(line terminator characters),否则将会失配:
- U+000A 换行符(“\n”)
- U+000D 回车符(“\r”)
- U+2028 行分隔符(line separator)
- U+2029 段分隔符(paragraph separator)
这实际上意味着".“将会匹配任意的单个Unicode Basic Multilingual Plane (BMP)字符。若要使其与astral字符(大于\uFFFF的Unicode字符)匹配,你应当使用"u”(Unicode)修饰符。一起使用这两个修饰符,"."将无一例外地匹配任意Unicode字符。
属性描述符
RegExp.prototype.dotAll 属性的属性特性: |
|
writable | false |
enumerable | false |
configurable | true |
3. global
属性
针对字符串中所有可能的匹配项测试正则表达式,还是仅针对第一个匹配项。
global 的值是布尔对象,如果使用了 “g” 标志,则返回 true;否则返回 false。 “g” 标志意味着正则表达式应该测试字符串中所有可能的匹配。
你无法直接更改此属性。
属性描述符
RegExp.prototype.global 属性的属性特性: |
|
writable | false |
enumerable | false |
configurable | false |
例子
var regex = new RegExp("foo", "g") console.log(regex.global) // true
4. ignoreCase
属性
匹配文本的时候是否忽略大小写。
ignoreCase 的值是布尔对象,如果使用了"i" 标志,则返回 true;否则,返回 false。“i” 标志意味着在字符串进行匹配时,应该忽略大小写。
你无法直接更改此属性。
属性描述符
RegExp.prototype.ignoreCase 属性的属性特性: |
|
writable | false |
enumerable | false |
configurable | false |
例子
var regex = new RegExp("foo", "i") console.log(regex.ignoreCase) // true
5. multiline
属性
是否进行多行搜索。
multiline 是一个布尔对象,如果使用了 “m” 标志,则返回 true;否则,返回 false。“m” 标志意味着一个多行输入字符串被看作多行。例如,使用 “m”,“^” 和 “$” 将会从只匹配正则字符串的开头或结尾,变为匹配字符串中任一行的开头或结尾。
你无法直接更改此属性。
属性描述符
RegExp.prototype.multiline 属性的属性特性: |
|
writable | false |
enumerable | false |
configurable | false |
例子
var regex = new RegExp("foo", "m") console.log(regex.multiline) // true
6. source
属性
正则表达式的文本。
该属性返回一个值为当前正则表达式对象的模式文本的字符串,该字符串不会包含正则字面量两边的斜杠以及任何的标志字符。
例子
var regex = /fooBar/ig; console.log(regex.source); // "fooBar",不包含 /.../ 和 "ig"。
7. sticky
属性
该属性是正则表达式对象的只读属性,表示搜索是否是 sticky(粘性),即仅从正则表达式的 lastIndex 属性表示的索引处搜索 。
sticky 的值是
Boolean
,并在 y 标志使用时为真; 否则为假。y 标志指示,仅从正则表达式的 lastIndex 属性表示的索引处为目标字符串匹配(并且不会尝试从后续索引匹配)。如果一个表达式同时指定了 sticky 和 global,其将会忽略 global 标志。你不能直接更改这个属性,它是只读的。
例子
使用带 sticky 标志的正则表达式:
var str = '#foo#'; var regex = /foo/y; regex.lastIndex = 1; regex.test(str); // true (译注:此例仅当 lastIndex = 1 时匹配成功,这就是 sticky 的作用) regex.lastIndex = 5; regex.test(str); // false (lastIndex 被 sticky 标志考虑到,从而导致匹配失败) regex.lastIndex; // 0 (匹配失败后重置)
8.unicode
属性
Unicode 功能是否开启。即该属性表明正则表达式带有 "u"
标志。 unicode 是正则表达式独立实例的只读属性。
例如:
var regex = new RegExp('\u{61}', 'u'); console.log(regex.unicode); // true
4.3 实例方法
方法名 | 描述 | 说明 |
用于在脚本执行过程中(重新)编译正则表达式 | 已废弃,改用 RegExp 对象的构造函数 | |
RegExp.prototype.exec() | 在该字符串中执行匹配项的搜索。 | |
RegExp.prototype.test() | 该正则在字符串里是否有匹配。 | |
RegExp.prototype[@@match]() | 对给定字符串执行匹配并返回匹配结果。 | |
RegExp.prototype[@@matchAll]() | 对给定字符串执行匹配,返回所有匹配结果。 | |
RegExp.prototype[@@replace]() | 给定新的子串,替换所有匹配结果。 | |
RegExp.prototype[@@search]() | 在给定字符串中搜索匹配项,并返回在字符串中找到字符索引。 | |
RegExp.prototype[@@split]() | 通过将给定字符串拆分为子字符串,并返回字符串形成的数组。 | |
非标准: |
返回一个字符串,代表当前对象的源代码 | 该特性是非标准的,请尽量不要在生产环境中使用它! |
RegExp.prototype.toString() | 返回表示指定对象的字符串。重写Object.prototype.toString()方法。 |
4.3.1 已废弃:RegExp.prototype.compile()方法
已废弃的compile() 方法被用于在脚本执行过程中(重新)编译正则表达式。与RegExp构造函数基本一样。
不推荐compile方法,可以使用 RegExp 构造函数来得到相同效果
语法
regexObj.compile(pattern, flags)
参数
pattern
正则表达式的文本flags
如果指定,标志可以具有以下值的任意组合:
标志(flag) | 描述 |
g |
全局匹配 |
i |
忽略大小写 |
m |
多行;让开始和结束字符(^ 和 $)工作在多行模式工作(例如,^ 和 $ 可以匹配字符串中每一行的开始和结束(行是由 \n 或 \r 分割的),而不只是整个输入字符串的最开始和最末尾处。 |
y |
黏度; 在目标字符串中,只从正则表达式的lastIndex属性指定的显示位置开始匹配(并且不试图从任何之后的索引匹配)。 |
使用compile
方法:
regexObj.compile("new foo", "g");
相应改为使用构造函数的写法:
var regexObj = new RegExp("foo", "gi");
4.3.2 RegExp.prototype.exec()方法
在该字符串中执行匹配项的搜索。
// 匹配 "quick brown" 后跟 "jumps",忽略中间的字符 // 记住 "brown" 和 "jumps" // 忽略大小写 var re = /quick\s(brown).+?(jumps)/ig; var result = re.exec('The Quick Brown Fox Jumps Over The Lazy Dog');
对象 | 属性/索引 | 描述 | 例子 |
result |
[0] |
匹配的全部字符串 | Quick Brown Fox Jumps |
[1], ...[*n* ] |
括号中的分组捕获 | [1] = Brown[2] = Jumps |
|
index |
匹配到的字符位于原始字符串的基于0的索引值 | 4 |
|
input |
原始字符串 | The Quick Brown Fox Jumps Over The Lazy Dog |
|
re |
lastIndex |
下一次匹配开始的位置 | 25 |
ignoreCase |
是否使用了 “i ” 标记使正则匹配忽略大小写 |
true |
|
global |
是否使用了 “g ” 标记来进行全局的匹配. |
true |
|
multiline |
是否使用了 “m ” 标记使正则工作在多行模式(也就是,^ 和 $ 可以匹配字符串中每一行的开始和结束(行是由 \n 或 \r 分割的),而不只是整个输入字符串的最开始和最末尾处。) |
false |
|
source |
正则匹配的字符串 | quick\s(brown).+?(jumps) |
语法
regexObj.exec(str)
参数
str
要匹配正则表达式的字符串。
返回值
情形 | 返回值 |
匹配成功 | 返回一个数组(包含额外的属性 index 和 input ,参见下方表格),并更新正则表达式对象的 lastIndex 属性。完全匹配成功的文本将作为返回数组的第一项,从第二项起,后续每项都对应正则表达式内捕获括号里匹配成功的文本。 |
匹配失败 | 返回 null,并将 lastIndex 重置为 0 。 |
例子:查找所有匹配
当正则表达式使用 "g"
标志时,可以多次执行 exec
方法来查找同一个字符串中的成功匹配。当你这样做时,查找将从正则表达式的 lastIndex
属性指定的位置开始。(test
() 也会更新 lastIndex
属性)。注意,即使再次查找的字符串不是原查找字符串时,lastIndex
也不会被重置,它依旧会从记录的 lastIndex
开始。
例如:
var myRe = /ab*/g; var str = 'abbcdefabh'; var myArray; while ((myArray = myRe.exec(str)) !== null) { var msg = 'Found ' + myArray[0] + '. '; msg += 'Next match starts at ' + myRe.lastIndex; console.log(msg); }
运行结果为:
Found abb. Next match starts at 3 Found ab. Next match starts at 9
4.3.3 RegExp.prototype.test()方法
test()
方法执行一个检索,用来查看正则表达式与指定的字符串是否匹配。返回 true 或 false。
语法
regexObj.test(str)
参数
str
用来与正则表达式匹配的字符串
返回值
情形 | 返回值 |
匹配成功 | true |
匹配失败 | false |
例子
测试hello
是否在字符串str
开始:
let str = 'hello world!'; let result = /^hello/.test(str); console.log(result);
Out[]:
true
4.3.4 RegExp.prototype[@@match
]()方法
该方法为自定义 RegExp 子类中的匹配行为而存在。
该方法用于获取匹配结果。这个方法在 String.prototype.match() 的内部调用。例如,下面的两个方法返回相同结果。
'abc'.match(/a/); /a/[Symbol.match]('abc');
语法
regexp[Symbol.match](str)
参数
参数 | 描述 |
str |
match 的目标字符串 |
例子
直接调用
这个方法的使用方式和 String.prototype.match() 相同,不同之处是 this 和参数顺序。
var re = /[0-9]+/g; var str = '2022-01-02'; var result = re[Symbol.match](str); console.log(result); // ["2022", "01", "02"]
在子类中调用
RegExp 的子类可以覆写 @@match方法来修改默认行为。
class MyRegExp extends RegExp { [Symbol.match](str) { var result = RegExp.prototype[Symbol.match].call(this, str); if (!result) return null; return { group(n) { return result[n]; } }; } } var re = new MyRegExp('([0-9]+)-([0-9]+)-([0-9]+)'); var str = '2016-01-02'; var result = str.match(re); // String.prototype.match 调用 re[@@match]. console.log(result.group(1)); // 2016 console.log(result.group(2)); // 01 console.log(result.group(3)); // 02
4.3.5 RegExp.prototype[@@matchAll]()方法
该方法返回对字符串使用正则表达式的所有匹配项。
语法
regexp[Symbol.matchAll](str)
参数
参数 | 描述 |
str |
一个String的匹配对象。 |
例子
直接调用
除了this
的不同以及参数顺序的的差异,本方法的使用方法几乎与 String 的 matchAll
() 方法相同。
var re = /[0-9]+/g; var str = '2016-01-02'; var result = re[Symbol.matchAll](str); console.log(Array.from(result, x => x[0])); // ["2016", "01", "02"]
在子类中使用@@matchAll
RegExp的子类可以重写@@matchAll方法来修改默认行为。例如,返回一个Array而不是iterator:
class MyRegExp extends RegExp { [Symbol.matchAll](str) { var result = RegExp.prototype[Symbol.matchAll].call(this, str); if (!result) { return null; } else { return Array.from(result); } } } var re = new MyRegExp('([0-9]+)-([0-9]+)-([0-9]+)', 'g'); var str = '2016-01-02|2019-03-07'; var result = str.matchAll(re); console.log(result[0]); // [ "2016-01-02", "2016", "01", "02" ] console.log(result[1]); // [ "2019-03-07", "2019", "03", "07" ]
4.3.6 RegExp.prototype[@@replace]()方法
该方法会在一个字符串中用给定的替换器,替换所有符合正则模式的匹配项,并返回替换后的新字符串结果。用来替换的参数可以是一个字符串或是一个针对每次匹配的回调函数。
语法
regexp[Symbol.replace](str, newSubStr|function)
参数
参数 | 描述 |
str |
正则替换的目标字符串。 |
newSubStr (replacement) |
类型为 String 的替换器。支持大多数特殊的替换匹配模式; 见String.prototype.replace()页的Specifying a string as a parameter部分。 |
function (replacement) |
生成新的子字符串的回调函数替换器。 |
返回值
用替换器替换相应匹配项后的新字符串。
4.3.7 RegExp.prototype[@@search]()方法
语法
regexp[Symbol.search](str)
参数
参数 | 描述 |
str | 搜索的目标 String |
例子
在子类中使用@@search——{jsxref(“RegExp”)}} 的子类可以覆写 @@search方法来修改默认行为。
class MyRegExp extends RegExp { constructor(str) { super(str) this.pattern = str; } [Symbol.search](str) { return str.indexOf(this.pattern); } } var re = new MyRegExp('a+b'); var str = 'ab a+b'; var result = str.search(re); // String.prototype.search 调用 re[@@search]. console.log(result); // 3
返回值
状态 | 返回值 |
匹配成功 | 返回该正则模式的第一个匹配项的在字符串中的位置索引 |
匹配失败 | 返回-1 |
4.3.8 RegExp.prototype[@@split]()方法
如果切割器是一个RegExp对象,这个方法就将在 String.prototype.split() 的内部调用。例如,下面的两个方法返回相同结果。如果str参数不是一个RegExp 对象, String.prototype.split() 就不会调用该方法,也不会创建一个 RegExp 对象。
'a-b-c'.split(/-/); /-/[Symbol.split]('a-b-c');
语法
RegExp.prototype[@@split]()
参数 | 描述 |
str |
切割操作的目标字符串 |
limit 可选 |
一个为了限制切割数量的特定整数。 @@split 仍会切割每个匹配正则模式的匹配项,直到切割数量达到该限制数,除非提前切割完字符串。 |
返回值
包含其子字符串的Array 。
例子
直接调用
这个方法的使用方式和 String 的 split
() 方法效果相同,不同之处是 this 和参数顺序。
var re = /-/g; var str = '2016-01-02'; var result = re[Symbol.split](str); console.log(result); // ["2016", "01", "02"]
在子类中使用 @@split
RegExp 的子类可以覆写 @@split方法来修改默认行为。
class MyRegExp extends RegExp { [Symbol.split](str, limit) { var result = RegExp.prototype[Symbol.split].call(this, str, limit); return result.map(x => "(" + x + ")"); } } var re = new MyRegExp('-'); var str = '2016-01-02'; var result = str.split(re); // String.prototype.split 调用 re[@@split]. console.log(result); // ["(2016)", "(01)", "(02)"]
4.3.9 非标准:RegExp.prototype.toSource()方法
返回一个字符串,代表当前对象的源代码。
语法
regexObj.toSource()
返回值
- 对于内置的
RegExp
对象,toSource()
方法返回如下字符串:
function RegExp() { [native code] }
- 对于一个
RegExp
实例,toSource()
方法返回代表该正则的字符串。
4.3.10 RegExp.prototype.toString()方法
返回一个表示该正则表达式的字符串。
RegExp 对象覆盖了 Object 对象的 toString() 方法,并没有继承 Object.prototype.toString()。对于 RegExp 对象,toString 方法返回一个该正则表达式的字符串形式。
语法
regexObj.toString()
例子
输出 RegExp 对象的字符串值:
myExp = new RegExp("a+b+c"); console.log(myExp.toString());
Out[1]:
“/a+b+c/”
foo = new RegExp("bar", "g"); console.log(foo.toString());
Out[2]:
“/bar/g”
附录: 查询
元字符表
字符 | 描述 |
\ |
将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,‘n’ 匹配字符 “n”。‘\n’ 匹配一个换行符。序列 ‘\’ 匹配 “” 而 “(” 则匹配 “(”。 |
^ |
匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 ‘\n’ 或 ‘\r’ 之后的位置。 |
$ |
匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 ‘\n’ 或 ‘\r’ 之前的位置。 |
* |
匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,}。 |
+ |
匹配前面的子表达式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。 |
? |
匹配前面的子表达式零次或一次。例如,“do(es)?” 可以匹配 “do” 或 “does” 。? 等价于 {0,1}。 |
{n} |
n 是一个非负整数。匹配确定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。 |
{n,} |
n 是一个非负整数。至少匹配n 次。例如,‘o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。‘o{1,}’ 等价于 ‘o+’。‘o{0,}’ 则等价于 ‘o*’。 |
{n,m} |
m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,“o{1,3}” 将匹配 “fooooood” 中的前三个 o。‘o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格。 |
? |
当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 “oooo”,‘o+?’ 将匹配单个 “o”,而 ‘o+’ 将匹配所有 ‘o’。 |
. |
匹配除换行符(\n、\r)之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,请使用像"(.|\n)"的模式。 |
(pattern) |
匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 ‘(’ 或 ‘)’。 |
(?:pattern) |
匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 “或” 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 ‘industry|industries’ 更简略的表达式。 |
(?=pattern) |
正向肯定预查(look ahead positive assert),在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)“能匹配"Windows2000"中的"Windows”,但不能匹配"Windows3.1"中的"Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?!pattern) |
正向否定预查(negative assert),在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如"Windows(?!95|98|NT|2000)“能匹配"Windows3.1"中的"Windows”,但不能匹配"Windows2000"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?<=pattern) |
反向(look behind)肯定预查,与正向肯定预查类似,只是方向相反。例如,"`(?<=95 |
(?<!pattern) |
反向否定预查,与正向否定预查类似,只是方向相反。例如"`(?<!95 |
x|y |
匹配 x 或 y。例如,‘z|food’ 能匹配 “z” 或 “food”。‘(z|f)ood’ 则匹配 “zood” 或 “food”。 |
[xyz] |
字符集合。匹配所包含的任意一个字符。例如, ‘[abc]’ 可以匹配 “plain” 中的 ‘a’。 |
[^xyz] |
负值字符集合。匹配未包含的任意字符。例如, ‘[^abc]’ 可以匹配 “plain” 中的’p’、‘l’、‘i’、‘n’。 |
[a-z] |
字符范围。匹配指定范围内的任意字符。例如,‘[a-z]’ 可以匹配 ‘a’ 到 ‘z’ 范围内的任意小写字母字符。 |
[^a-z] |
负值字符范围。匹配任何不在指定范围内的任意字符。例如,‘[^a-z]’ 可以匹配任何不在 ‘a’ 到 ‘z’ 范围内的任意字符。 |
\b |
匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。 |
\B |
匹配非单词边界。‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。 |
\cx |
匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符。 |
\d |
匹配一个数字字符。等价于 [0-9]。 |
\D |
匹配一个非数字字符。等价于 [^0-9]。 |
\f |
匹配一个换页符。等价于 \x0c 和 \cL。 |
\n |
匹配一个换行符。等价于 \x0a 和 \cJ。 |
\r |
匹配一个回车符。等价于 \x0d 和 \cM。 |
\s |
匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 |
\S |
匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 |
\t |
匹配一个制表符。等价于 \x09 和 \cI。 |
\v |
匹配一个垂直制表符。等价于 \x0b 和 \cK。 |
\w |
匹配字母、数字、下划线。等价于’[A-Za-z0-9_]'。 |
\W |
匹配非字母、数字、下划线。等价于 ‘[^A-Za-z0-9_]’。 |
\xn |
匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,‘\x41’ 匹配 “A”。‘\x041’ 则等价于 ‘\x04’ & “1”。正则表达式中可以使用 ASCII 编码。 |
\num |
匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,‘(.)\1’ 匹配两个连续的相同字符。 |
\n |
标识一个八进制转义值或一个向后引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。 |
\nm |
标识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。 |
\nml |
如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。 |
\un |
匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。 |
优先级(从上到下)
运算符 | 描述 |
\ |
转义符 |
() , (?:) , (?=) , [] 圆括号和方括号 |
|
* , + , ? , {n} , {n,} , {n,m} |
限定符 |
^ , $ , \任何元字符、任何字符 |
定位点和序列(即:位置和顺序) |
` | ` |
标记
标记 | 含义 | 描述 |
i | ignore - 不区分大小写 | 将匹配设置为不区分大小写,搜索时不区分大小写: A 和 a 没有区别。 |
g | global - 全局匹配 | 查找所有的匹配项。 |
m | multi line - 多行匹配 | 使边界字符 ^ 和 $ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾。 |
s | 特殊字符圆点 . 中包含换行符 \n | 默认情况下的圆点 . 是 匹配除换行符 \n 之外的任何字符,加上 s 修饰符之后, . 中包含换行符 \n。 |
参考资料
[1] jcLee95 的 CSDN 博文 => Python 正则表达式https://blog.csdn.net/qq_28550263/article/details/123482797
[2] 菜鸟教程 => 正则表达式(https://www.runoob.com/regexp/regexp-tutorial.html)
[3] MDN web Docs => JavaScript 参考https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference