JS正则

两种表达式

1.对象字面量
以斜杠/表示开始和结束.

1
let regx = /xyz/;

2.使用RegExp构造函数.

1
let regx = new RegExp("xyz");

两种方法等价,区别在于第一种在引擎编译代码时,新建正则表达式.
第二种在运行时新建正则表达式.

第二参数

1
2
3
let regx = /xyz/g;
//等价于
let regx = new RegExp("xyz", "g");

实例方法

RegExp.prototype.test()

返回一个布尔值,表示当前模式是否能够匹配参数表达式.

1
/cat/.test("cats and dogs"); // true

验证字符串中是否含有cat.
如果含有g修饰符,则每一次test方法都从上一次结束的位置开始向后匹配.

1
2
3
4
5
6
let r = /z/g;
let s = "_z_z";

r.test(s); //true,(从第一个_z前面开始)
r.test(s); //true,(从第二个_z前面开始)
r.test(s); //false,(从第二个_z后面开始)

g修饰符表示全局搜索.
如果正则是一个空字符串,则会匹配所有的字符串.

1
new RegExp("").test("abc"); //true

RegExp.prototype.exec()

返回匹配结果.如果发现匹配,即返回一个数组.成员是匹配成功的子字符串,否则返回null.

1
2
3
4
5
6
let s = "_X_X";
let r1 = /x/;
let r2 = /y/;

r1.exec(s); //["x"]
r2.exec(s); // null

组匹配

正则如果包含(),则返回的数组包含多个成员.
第一个成员是整个匹配成功的结果.第二个成员对应第一个括号,第二个成员对应第二个括号.

1
2
3
let s = "_x_x";
let r = /_(x)/;
r.exec(s); //["_x", "x"]

Srting.prototype.match()

字符串实例对象的match方法对字符串进行正则匹配,返回匹配结果.

1
2
3
4
5
let s = "_x_x";
let r1 = /x/;
let r2 = /y/;
s.match(r1); //["x"}
s.match(r2); //

字符串的match方法与正则对象的exec非常类似.
匹配成功返回一个数组,匹配失败返回 null.
如果正则表达式带有g修饰符,则该方法与exec不同,会一次性返回所有匹配成功的结果.

1
2
3
4
let s = "abba";
let r = /a/g;
s.match(r); //["a","a"]
s.exec(r); //["a"]

返回第一个满足匹配结果在整个字符串的位置.如果没有返回-1.

1
'_x_x'search(/x/); //1

String.prototype.replace()

字符串对象的replace可以替换匹配的值.它接收两个参数,第一个是正则表达式.表示搜索模式.
第二个是替换内容.

1
str.replace(search, replacement);

如果不加g,就替换匹配成功的第一个值,否则替换所有值.

1
2
3
4
let str = "aaa";
str.replace(a, b); //"baa"
str.replace(/a/, b); //"baa"
str.replace(/a/g, b); //"bbb"

使用repalce消除字符串首尾两端的空格.

1
2
3
let str = "     #id div.class   ";
str.replace(/^\s+|\s+$/g, "");
//#id div.class

replace第二个参数可以使用美元符号$,用来指代所替换的内容.

$&:匹配的子字符串。
$`:匹配结果前面的文本。
$’:匹配结果后面的文本。
$n:匹配成功的第 n 组内容,n 是从 1 开始的自然数。
$$:指代美元符号$。

1
2
3
let str = "abc";
str.replace("b", "[$`-$&-$']");
//"a[a-b-c]c"

作为 replace 方法第二个参数的替换函数,可以接受多个参数。其中,第一个参数是捕捉到的内容,第二个参数是捕捉到的组匹配(有多少个组匹配,就有多少个对应的参数)。此外,最后还可以添加两个参数,倒数第二个参数是捕捉到的内容在整个字符串中的位置(比如从第五个位置开始),最后一个参数是原字符串。

String.prototype.split()

该方法接收两个参数,第一个参数是正则表达式,表示分隔规则,第二个参数是返回数组的最大成员数.

1
2
3
4
5
6
7
8
9
10
11
// 非正则分隔
"a, b,c, d".split(",");
// [ 'a', ' b', 'c', ' d' ]

// 正则分隔,去除多余的空格
"a, b,c, d".split(/, */);
// [ 'a', 'b', 'c', 'd' ]

// 指定返回数组的最大成员
"a, b,c, d".split(/, */, 2);
//[ 'a', 'b' ]
1
2
3
4
5
6
7
// 例一
"aaa*a*".split(/a*/);
// [ '', '*', '*' ]

// 例二
"aaa**a*".split(/a*/);
// ["", "*", "*", "*"]

上面代码的分割规则是 0 次或多次的 a,由于正则默认是贪婪匹配,所以例一的第一个分隔符是 aaa,第二个分割符是 a,将字符串分成三个部分,包含开始处的空字符串。例二的第一个分隔符是 aaa,第二个分隔符是 0 个 a(即空字符),第三个分隔符是 a,所以将字符串分成四个部分。

如果正则表达式带有括号,则括号匹配的部分也会作为数组成员返回。

1
2
"aaa*a*".split(/(a*)/);
// [ '', 'aaa', '*', 'a', '*' ]

匹配规则

点字符

点字符匹配除回车\r,换行\n,行分隔符\u2028,段分隔符\2029以外的所有字符

1
/c.t/;

上面代码中,c.t 匹配 c 和 t 之间包含任意一个字符的情况,只要这三个字符在同一行,比如 cat、c2t、c-t 等等,但是不匹配 coot。

位置字符

提示字符所处的位置.

1
2
3
4
5
6
7
8
9
10
^ 表示字符串的开始位置
$ 表示字符串的结束位置
\b 单词边界的位置
\B 非单词边界的位置
x(?=p) x后面的字符与p匹配时匹配x,即匹配p前面的位置
比如对于/Jack(?=Sprat)/,“Jack”在跟有“Sprat”的情况下才会得到匹配.
x(?!p) x后面的字符不与p匹配时匹配x,即匹配非p前面的位置
(?<=p)x x前面的字符与p匹配时匹配x,即匹配p后面的位置
例如,对于/(?<=Jack)Sprat/,“Sprat”紧随“Jack”时才会得到匹配。
(?<!p)x x前面的字符不与p匹配时匹配x,即匹配非p后面的位置

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 在字符串首尾(即^和$)处插入“#”
"javascript css html".replace(/^|$/g, "#"); // "#javascript css html#"

// 在单词边界(即\b)处插入“#”
"javascript css html".replace(/\b/g, "#"); // "#javascript# #css# #html#"
// 非单词边界(即\B)处插入“#”
"javascript css html".replace(/\B/g, "#"); // "j#a#v#a#s#c#r#i#p#t c#s#s h#t#m#l"

// 在空格前的位置插入“#”
"javascript css html".replace(/(?=\s)/g, "#"); // "javascript# css# html"
// 在非空格前的位置插入“#”
"javascript css html".replace(/(?!\s)/g, "#"); // "#j#a#v#a#s#c#r#i#p#t #c#s#s #h#t#m#l#"

// 在空格后的位置插入“#”
"javascript css html".replace(/(?<=\s)/g, "#"); // "javascript #css #html"
// 在非空格后的位置插入“#”
"javascript css html".replace(/(?<!\s)/g, "#"); // "#j#a#v#a#s#c#r#i#p#t# c#s#s# h#t#m#l#"

选择符(|)

竖线符号在正则表达式中表示”或关系”

转义符

正则表达式中那些有特殊含义的元字符,如果要匹配它们本身,就需要在它们前面要加上反斜杠。比如要匹配+,就要写成\+
正则表达式中,需要反斜杠转义的,一共有 12 个字符:^.[$()|*+?{\\。需要特别注意的是,如果使用RegExp方法生成正则对象,转义需要使用两个斜杠,因为字符串内部会先转义一次。

特殊字符

\cX 表示Ctrl-[X],其中的 X 是 A-Z 之中任一个英文字母,用来匹配控制字符。
[\b] 匹配退格键(U+0008),不要与\b混淆。
\n 匹配换行键。
\r 匹配回车键。
\t 匹配制表符 tab(U+0009)。
\v 匹配垂直制表符(U+000B)。
\f 匹配换页符(U+000C)。
\0 匹配 null 字符(U+0000)。
\xhh 匹配一个以两位十六进制数(\x00-\xFF)表示的字符。
\uhhhh 匹配一个以四位十六进制数(\u0000-\uFFFF)表示的 Unicode 字符。

匹配带千分位的金额,并以正常字符串输出

1
2
num = s.match(/\d*(\,\d+)*(\.\d+)?/g)[0].replace(/\,/gi, "");
//匹配带千分位的金额,并以正常字符串输出

量词

贪婪模式

尽可能多的匹配

1
2
3
4
5
6
x{m,n}	x出现的次数为m-n次
x{m,} x至少出现m次
x{m} x出现m次,相当于{m,m}
x? x出现01次,相当于{0,1}
x+ x出现1或多次,相当于{1,}
x* x出现0或多次,相当于{0,}

在 x{m,n}中,x 表示待匹配的项,可以是一个字符或一个整体,m 为 0 或者正整数,n 为正整数,且 n>m。

例子 1:/a{2,4}bc/中 a{2,4}指的是字符串中 a 出现的次数是 2-4 次

1
2
3
4
const regExp = /a{2,4}bc/;
regExp.test("aaabc"); // true
regExp.test("aabc"); // true
regExp.test("abc"); // false

非贪婪模式

尽可能少的匹配

1
2
3
4
5
x{m,n}?	x出现的次数m-n次
x{m,}? x至少出现m次
x?? x出现01次,相当于{0,1}
x+? x出现1或多次,相当于{1,}
x*? x出现0或多次,相当于{0,}

上面我们讲的重复字符都是尽可能多地匹配,这种我们称为贪婪的匹配,同时我们还有非贪婪的匹配(也可以叫惰性匹配),它是尽可能少的匹配。
语法:在表示量词后跟随一个“?”。

例子 1:使用”aaa”作为匹配字符串,用正则表达式/a+/去匹配,匹配的结果是”aaa”,用/a+?/匹配的结果是”a”。

1
2
3
4
5
"aaa".match(/a+/);
// ["aaa", index: 0, input: "aaa", groups: undefined]

"aaa".match(/a+?/);
// ["a", index: 0, input: "aaa", groups: undefined]

修饰符

1
2
3
4
5
6
i 不区分大小写
g 全局匹配,查找所有的匹配项,没有 g 修饰符的话匹配到第一个就停止了
m 多行匹配模式,^/$匹配一行或者字符串的开头/结尾
s 允许.匹配换行符
u 使用 unicode 码的模式进行匹配。
y 执行“粘性(sticky)”搜索,匹配从目标字符串的当前位置开始。

圆括号的作用

1
2
3
4
5
6
7
8
9
(x) 捕获组:匹配 x 并将括号内的正则表达式定义为一个子表达式,
供后面反向引用使用或者获取子表达式匹配结果。
使用结果元素的索引 ([1], ..., [n]) 或
从预定义的  RegExp  对象的属性 ($1, ..., $9)来获取。
捕获组会带来性能损失,如果你不需要存储匹配项或者你的括号只是分组作用,
可以选择下面的非捕获组。
(?:x) 非捕获组:匹配 x 并且不定义子表达式,只用括号最原始的功能
\n 反向引用:n 是一个正整数,引用之前出现的分组,\1 表示正则中与第一个左括号相匹配的子表达式
(?<Name>x) 具名捕获组:匹配 x 并将其存储在返回的匹配项的 groups 属性中
1
2
/^abc{3}$/  //abccc
/^(abc){3}$/ abcabcabc //abc 重复 3 次