发布日期 » 2017年11月9日 星期四

版权声明 » 帅华君原创文章,未经允许不得转载。

正则表达式速记

除了RegExp对象的exec()方法和test()方法用于正则匹配,String对象亦拥有正则匹配的方法,比如search(),replace(),match(),split()。帅华君将这些内容梳理起来便于记忆和查阅。

书越读越薄,越品越厚

记得这句话是帅华君上小学的时候经常被老师放在嘴边的话,意思是,书本上的知识不全都适合所有阅读者,通读后一遍后,摘选自己还没有掌握的知识,放入自己的知识架构中,所以这样读一遍下来书就变薄了。

在日后的知识的应用中,不断回想、品思书中精华,举一反三,将新知识加入自己的 “书” 中,心中的那本书便又越来越厚了。

所以可见,一般总结性的文章并不见得适合所有人阅读,他是作者 的浓缩精华部分,难免会丢失 原书 中的知识。因此对于初学者,建议追本溯源,从而让你的那本 越来越厚。

创建正则表达式 Regular Express

var pattern = /shuaihua/;
var re = new RegExp('shuaihua');

有两种创建正则表达式的方法:

  • 使用 正则表达式直接量
  • 使用 RexExp构造函数

常用正则匹配规则

(1)直接量字符

字符 匹配
字母和数字字符 自身
\o NUL字符(\u0000)
\t 制表符(\u0009)
\n 换行符(\u000A)
\v 垂直制表符(\u000B)
\f 换页符(\u000C)
\r 回车符(\u000D)
\xnn 由十六进制数 nn 指定的拉丁字符,例如,\x0A 等价于 \n
\uxxxx 由十六进制数 xxxx 指定的 Unicode 字符,例如\u0009等价于\t
\cX 控制字符 ^X,例如,\cJ等价于换行符\n

还有一些直接量字符:

^ $ . + ? = ! : | \ / ( ) [ ] { } *

如果想在正则表达式中使用这些字符的直接量进行匹配,则必须使用前缀 \,这是一条通行规则。(@和引号并没有其他意义,如果需要用反斜杠的直接量同样需要使用反斜杠转义 /\/匹配任何包含反斜杠的字符串。)

(2)字符类(character class)

直接量字符单独当今方括号[]内就组成了字符类,自负累可以匹配它所包含的任意字符。

[abc] 匹配a或b或c

使用连字符 - 表示字符范围。

[a-zA-Z0-9] 表示匹配拉丁字符中任何字母和数字。

除了使用中括号和其中包含的直接量字符表示字符类,JavaScript中还提供了一些转义字符来表示字符类:

字符 匹配
[...] 方括号内的任意字符
[^...] 不在方括号内的任意字符
. 除换行符和其他Unicode行终止符之外的任意字符
\w 任何ASCII字符组成的单词,等价于[a-zA-Z0-9]
\W 任何不是ASCII字符组成的单词,等价于[^a-zA-Z0-9]
\s 任何Unicode空白符
\S 任何非Unicode空白符,注意\w和\S不同
\d 任何ASCII数字,等价于[0-9]
\D 除了ASCII数字之外的任何字符,等价于[^0-9]
[\b] 退格直接量,特例

(3)重复出现次数

字符 含义
{m,n} 匹配前一项至少n次,但不能超过m次
{n,} 匹配前一项n次或者更多次
{n} 匹配前一项n次
? 匹配前一项0次或者1次
+ 匹配前一项至少一次
* 匹配前一项0次或者更多次

上面的重复模式如果单独使用,原则上匹配的越多越好,然而很多时候我们希望适可而止,于是就有了非贪婪的重复。

非贪婪重复

??+??{2,4}?

(4)选择、分组、引用

字符 含义
| 选择,匹配的是该符号左边的子表达式或右边的子表达式
(...) 组合,将几个项组合成一个单元,这个单元可以通过 * + ? 和 | 等符号加以修饰,而且可以记住和这个组合相匹配的字符以便于后方引用。
(?:...) 只组合,把项组合到一个单元中,但不记忆与该组相匹配的字符
\n 和第n个分组第一次匹配的字符相匹配,组是圆括号中的子表达式(也有可能是嵌套的),组索引是从左到右的左括号数,注意(?:形式的分组不编码。

使用竖线 | 来指定选择项。

使用括号 () 来分组和引用。

  • ()仅仅用作将单独的项组合成子表达式
  • ()定义完整模式中的子模式(用于提取需要的部分匹配结果)
  • ()允许在同一正则表达式的后部引用前面的子表达式(后面可以用 反斜杠加数字 表示要引用的前面已经匹配成功的字符)

(5)指定匹配位置

转义字符,除了匹配直接量字符,还能匹配位置。

字符 含义
^ 匹配字符串的结尾,在多行检索模式中,还匹配一行的开头
$ 匹配字符串的结尾,在多行检索模式中,还匹配一行的结尾
\b 匹配一个单词的边界(即\w和\W之间的位置,或者位于\w字符开头或者结之间的位置)。(注意 [\b] 匹配的是退格符)
\B 匹配非单词边界的位置
(?=p) 零宽正向先行断言,要求接下来的字符与p匹配,但不能包括匹配p的那些字符
(?!p) 零宽负向断言,要求接下来的字符不与p匹配。

(6)修饰符

  • g 开启全局匹配模式
  • i 开启不区分大小写模式
  • m 开启多行匹配模式

(7)用于匹配模式的String方法

search()方法
  • 只需提供一个参数。
  • 参数为正则表达式字面量形式,如果不为字面量,则其内部通过RegExp构造函数转换成正则表达式。
  • 只匹配第一次,如果匹配成功则返回匹配成功的索引位置,如果匹配不成功,则返回 -1。
  • 不支持全局匹配,就算字面量 // 后添加 g 标志也会忽略。
replace()方法
  • 可提供两个参数。
  • 第一个参数为字符串(纯字符串)或者正则表达式的字面量(有两个反斜杠的那种)。
  • 如果第一个参数为正则字面量,且为全局模式,则全部替换,如果未指明全局模式则只置换第一个子串。
  • 如果第一个参数为纯字符串,则直接替换所有匹配字符串的的子串(并不会在内部转换成RegExp对象)。
  • 第二个参数是要替换成的字符,可以是字符也可以是一个回调函数。
  • 如果在第二个字符串中出现 $ 符号,那么这里就用到了括号的引用特性, $n 就会替换成引用的部分。
  • 第二个参数可以是回调函数,用来动态的计算替换字符串。
match()方法
  • 唯一一个参数,参数为正则表达式字面量,如果为字符串则内部转换成RegExp对象。
  • 如果正则表达式设置了全局模式,则返回包含所有匹配结果的数组。
  • 如果没设置全局模式,依然返回数组,为了和 replace 保持一致,数组中的 a[n] 存放的即为 $n。
split()方法
  • 传入一个参数,参数可以是字符串,亦可以是正则表达式字面量。
  • 将字符串按照参数拆分成一个数组,分隔符即为第一个参数。

(8)RegExp方法

构造函数
new RegExp('shuaihua','igm')
exec()方法

exec()方法与不开启全局模式的String对象的match方法返回值很类似。

test()方法的参数是一个字符串,返回值为布尔值,表示是否匹配成功。

需要注意的是,如果没有开启全局模式g,则实例化的RegExp对象中可读/写的lastIndex属性将不会重置为0,因此如果需要重新匹配,记得把lastIndex属性重置为0。