语法
在 JS 中,创建一个正则表达式的模式,可以有三种实现方式。
- 字面量
- 构造函数
- 工厂符号
/pattern/flags
new RegExp(pattern [, flags])
RegExp(pattern [, flags])
其中,pattern 就是正则表达式(模式),flags 是模式修饰符。
下面的几种正则表达式的写法,创建的正则表达式都是相同的。
/ab+c/i;
new RegExp('ab+c', 'i');
new RegExp(/ab+c/, 'i');
RegExp(/ab+c/, 'i');
模式修饰符(flags)
在 JS 中的正则表达式,支持的修饰符主要有:
- i 忽略大小写。
- g 全局匹配。找到所有匹配,而不是在第一个匹配后停止。
- m 多行模式匹配。开始和结束标记( ^ 和 $ )视为在多行上工作。也就是说,分别匹配每一行的开始和结束(由 \n 或 \r 分割),而不是只匹配整个目标字符串的最开始和最末尾处。
- u 将模式视为 Unicode 序列。
- y 粘性匹配。仅匹配目标字符串中此正则表达式的 lastIndex 属性指示的索引,并且不尝试从任何后续的索引匹配。
字符簇(Character Sets)
字符簇就是字符的集合(Character Sets),也叫字符集合。
字符簇的开始标记是 [ , 结束标记是 ] 。
例如,[abcd] 等价于 [a-d] 。
字符簇内部左侧的 ^ 表示对整个字符簇取反。例如,[^abc] 等价于 [^a-c]。
字符类别(Character Classes)
字符类别(Character Classes),可以用来表示某一类的字符。
- . 点号表示匹配除换行符以外的任何字符。注意,在字符簇中,点号没有特殊含义。
- \d 匹配任意的数字。等价于 [0-9] 。
- \D 匹配任意的非数字。 等价于 [^0-9] 。
- \w 匹配字母、数字、下划线。等价于 [A-Za-z0-9_] 。
- \W 和 \w 相反。等价于 [^A-Za-z0-9_] 。
- \s 匹配空白符,包括空格、制表符、换页符、换行符和其他 Unicode 空格。等价于 [ \f\n\r\t\v\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004 \u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f \u3000] 。
- \S 匹配非空白符。
- \t 匹配一个水平制表符(tab)。
- \r 匹配一个回车符(carriage return)。
- \n 匹配一个换行符(linefeed)。
- \v 匹配一个垂直制表符(vertical tab)。
- \f 匹配一个换页符(form-feed)。
- [\b] 匹配一个退格符(backspace)(不要与 \b 混淆)。
- \0 匹配一个 NULL 字符。不要在此后面跟小数点。
- \cX X 是 A-Z 的一个字母。匹配字符串中的控制字符。例如,/\cM/ 匹配字符串中的 control-M。
- \xhh 匹配编码为 hh (两个十六进制数字)的字符。
- \uhhhh 匹配 Unicode 值为 hhhh (四个十六进制数字)的字符。
边界(Boundaries)
- ^ 匹配整个字符串的头部,多行模式下也可以匹配行首。
- $ 匹配整个字符串的尾部,多行模式下也可以匹配行尾。
- \b 匹配一个零宽单词边界(zero-width word boundary),如一个字母和一个空格之间。例如,/\bno/ 匹配 "at noon" 中的 "no"。
- \B 匹配一个零宽非单词边界(zero-width non-word boundary),如两个字母之间或两个空格之间。例如,/\Bon/ 匹配 "at noon" 中的 "on"。
分组(Grouping)
分组就是在整个正则表达式中拆分出子表达式,也称为子组。
子组的开始标记是 ( , 结束标记是 ) 。
捕获子组
(x) 表示捕获子组,也就是说,子组的匹配结果会被捕获。
console.log( "foobar".match(/(foo)bar/) )
// ["foobar", "foo", index: 0, input: "foobar", groups: undefined]
被匹配的子字符串可以在结果数组的元素 [1], ..., [n] 中找到,或在被定义的 RegExp 对象的属性 $1, ..., $9 中找到。
捕获子组会影响性能,如果不需要再次访问被匹配的子字符串,最好使用非捕获子组。
反向引用
\n 表示反向引用。
反向引用指的是对捕获子组的匹配结果(子字符串)的引用。
n 是一个正整数,指向的是正则表达式中第 n 个小括号(从左开始数)中的子组(子表达式)匹配到的子字符串。
非捕获子组
(?:x) 表示非捕获子组,表示不单独捕获子组的匹配结果。
console.log( "foobar".match(/(?:foo)bar/) )
// ["foobar", index: 0, input: "foobar", groups: undefined]
可选分支
x|y 表示匹配 x 或 y 。
例如,/green|red/ 会匹配 "green apple" 中的 green,也会匹配 "red apple" 中的 red 。
量词(Quantifiers)
量词用来指定匹配的个数(次数),也称作限定符。
- {1} 限定次数为 1
- {3} 限定次数为 3
- {3,} 限定次数为 3 次及以上
- {1,3} 限定次数为 1-3 次
- ? 限定次数为 0 次或 1 次,等价于 {0,1}
- * 限定次数为 0 次及以上,等价于 {0,}
- + 限定次数为 1 次及以上,等价于 {1,}
量词可以对以下的元素的匹配次数进行限定。
- 单独的字符,可以是经过转义的
- 元字符
- 字符簇
- 反向引用
- 子组
如果没有明确指定量词,默认匹配次数为 1 次
断言(Assertions)
只有当断言为 true 时,才进行匹配。
上面说到的 【边界】(Boundaries),就是一种最简单的断言。
断言指的是对某个位置的匹配作出假设。断言部分不会出现在匹配结果中。
x(?=y)
仅匹配被 y 跟随的 x 。 /Jack(?=Sprat)/,如果 Jack 后面跟着 Sprat,则匹配 Jack 。但 Sprat 并不会出现在匹配结果中。
x(?!y)
仅匹配不被 y 跟随的 x 。 /\d+(?!\.)/ 只会匹配不被点号 . 跟随的数字。 /\d+(?!\.)/.exec('3.141') 匹配的是 141,而不是 3.141 。
使用正则表达式
在 JavaScript 中, 使用正则表达式主要有两种形式。
- RegExp 的 exec 和 test 方法
- String 的 match、search、replace 和 split 方法
RegExp 的 exec 和 test 方法
exec() 方法,用当前的正则表达式来匹配目标字符串。匹配成功,返回数组;失败返回 null 。
var myRe = /d(b+)d/;
var myArray = myRe.exec("cdbbd");
console.log(myArray);
// ["dbbd", "bb", index: 1, input: "cdbbd", groups: undefined]
test() 方法,测试当前的正则表达式能否匹配目标字符串。它返回 true 或 false 。
var res = /d(b+)d/.test("cdbbd");
console.log(res);
// true
String 的 match、search、replace 和 split 方法
match() 方法的作用和 exec() 一样,只是写法有区别。它返回一个数组或者在未匹配到时返回 null 。
var str = "cdbbd";
var myArray = str.match(/d(b+)d/);
console.log(myArray);
// ["dbbd", "bb", index: 1, input: "cdbbd", groups: undefined]
search() 方法,测试正则表达式在目标字符串中首次匹配成功的位置。如果匹配成功,返回匹配到的位置索引;失败时返回 -1 。
var res = "cdbbd".search(/d(b+)d/);
console.log(res);
// 1
replace() 方法,表示正则替换。使用替换字符串替换掉匹配到的子字符串。
var re = /(\w+)\s(\w+)/;
var str = "John Smith";
var newStr = str.replace(re, "$2, $1");
console.log(newStr);
// Smith, John
split() 方法,表示用正则表达式或字符串来将目标字符串分割为数组。
var myArray = "a=b=c".split(/=/);
console.log(myArray);
// ["a", "b", "c"]
var myArray = "a=b=c".split('=');
console.log(myArray);
// ["a", "b", "c"]