正则表达式(Regular Expression)是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。
在 JavaScript中,正则表达式也是对象。JavaScript通过内置对象RegExp支持正则表达式,有两种方式创建正则表达式对象

  1. 构造函数

    1
    new RegExp(pattern [, flags])
  2. 字面量

    1
    const regex = /ab+c/;

元字符

1
( [ { \ ^ $ | ) ? * + .

预定义的特殊字符

字符 正则 描述
\t /\t/ 制表符
\n /\n/ 制表符
\r /\r/ 回车符
\f /\f/ 换页符
\a /\a/ alert字符
\e /\e/ escape字符
\cX /\cX/ 与X相对应的控制字符
\b /\b/ 与回退字符
\v /\v/ 垂直制表符
\0 /\0/ 空字符

字符类

一般情况下正则表达式一个字符(转义字符算一个)对应字符串一个字符。但是我们可以使用元字符[]来构建一个简单的类,所谓类是指,符合某些特征的对象,是一个泛指,而不是特指某个字符了,我们可以使用表达式 [abc] 把字符a或b或c归为一类,表达式可以匹配这类的字符。

1
2
3
4
/[abc]/.test("a") // true
/[abc]/.test("ab") // true
/[abc]/.test("abc") // true
/[abc]/.test("abcd") // true

取反

元字符[]组合可以创建一个类,我们还可以使用元字符^创建反向类/负向类,反向类的意思是不属于XXX类的内容,表达式 [^abc] 表示不是字符a或b或c的内容,表示匹配不能为括号里面的字符

1
2
3
/[^abc]/.test("a") // false
/[^abc]/.test("ab") // false
/[^abc]/.test("hello") // true

范围类

按照上面的说明如果希望匹配单个数字那么表达式是这样的

1
[0123456789]

有时匹配的东西过多,而且类型又相同,全部输入太麻烦,我们可以用范围类。特征就是在中间加了个横线。如[0-9] [a-z] [A-Z]
要是想匹配所有字母呢?在[]组成的类内部是可以连写的,我们还可以这样写 [a-zA-Z]

预定义类

刚才使用正则我们创建了几个类,来表示数字,字母等,但这样写也很是麻烦,正则表达式为我们提供了几个常用的预定义类来匹配常见的字符

字符 等价类 含义
. [^\r\n] 除了回车符和换行符之外的所有字符
\d [0-9] 数字字符
\D [^0-9] 非数字字符
\s [\t\n\x0B\f\r] 空白符
\S [^\t\n\x0B\f\r] 非空白符
\w [a-zA-Z_0-9] 单词字符,字母、数字下划线
\W [^a-zA-Z_0-9] 非单词字符
1
2
3
4
5
6
/\d/.test("3") //true
/\d/.test("s") // false
/\D/.test("3") // false
/\s/.test(" ") // true
/./.test("哈哈") // true
/\w/.test("正则")

边界

正则表达式还提供了几个常用的边界匹配字符

字符 含义 描述
^ 以xxx开头 注意不能紧跟于左中括号的后面
$ 以xxx结尾
\b 单词边界 指[a-zA-Z_0-9]之外的字符
\B 非单词边界
1
2
/c+$/.test('abc') // true
/c+$/.test('abcd') // false

单词边界举例。要匹配的东西的前端或未端不能为英文字母阿拉伯字数字或下横线。

1
2
var str = "12w-eefd&efrew";
str.match(/\b\w+\b/g) // ["12w", "eefd", "efrew"]

量词

之前我们介绍的方法都是一一匹配的,如果我们希望匹配一个连续出现很多次数字的字符串难道我们需要写成这样\d\d\d\d...,为此正则表达式引入了一些量词

字符 含义
? 出现零次或一次(最多出现一次)
+ 出现一次或多次(至少出现一次)
* 出现零次或多次(任意次)
{n} 出现n次
{n,m} 出现n到m次
{n,} 至少出现n次
1
2
3
4
/\d{6}/.test("123456") // true
/\d{6}/.test("1234567") // true
/\d{6}/.test("12345") // false
/\d{6,8}/.test("123456789") // true

贪婪模式与非贪婪模式

贪婪模式,量词在默认下是尽可能多的匹配的,以这个表达式为例:a.*b,它将会匹配最长的以a开始,以b结束的字符串,如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。

1
'aabab'.match(/a.*b/g) // ["aabab"]

非贪婪模式,让正则表达式尽可能少的匹配,也就是说一旦成功匹配不再继续尝试,做法很简单,在量词后加上?即可

1
'aabab'.match(/a.*?b/g) // ["aab","ab"]

分组

到目前为止,我们只能一个字符到匹配,虽然量词的出现,能帮助我们处理一排密紧密相连的同类型字符。但这是不够的,下面该轮到小括号出场了,中括号表示范围内选择,大括号表示重复次数。小括号允许我们重复多个字符。

1
2
/(cat){3}/.test('catcatcatcat') // true
/(cat){3}/.test('catcat') // false

如果希望匹配cat或dog出现3次该怎么办呢?可以使用字符|达到或的功效

1
/(cat|dog){3}/.test('catcatcatdogdogdog') // true

反向分组

反向引用标识由正则表达式中的匹配组捕获的子字符串。每个反向引用都由一个编号或名称来标识,并通过“\编号”表示法进行引用。

1
/(dog)\1/.test("dogdog") // true

前瞻

继续在分组内做文章。前瞻与后瞻其实都属于零宽断言,但javascript不支持后瞻。

表达式 含义
exp1(?=exp2) 匹配后面是exp2的exp1
exp1(?!exp2) 匹配后面不是exp2的exp1
1
2
(/hello(?=world)/g).exec('helloworld12333') // ['hello']
(/hello(?=world)/g).exec('hellonextworld') // null

实例属性

实例属性 描述
global 是当前表达式模式首次匹配内容的开始位置,从0开始计数。其初始值为-1,每次成功匹配时,index属性都会随之改变。
ignoreCase 返回创建RegExp对象实例时指定的ignoreCase标志(i)的状态。如果创建RegExp对象实例时设置了i标志,该属性返回True,否则返回False,默认值为False。
lastIndex 是当前表达式模式首次匹配内容中最后一个字符的下一个位置,从0开始计数,常被作为继续搜索时的起始位置,初始值为-1, 表示从起始位置开始搜索,每次成功匹配时,lastIndex属性值都会随之改变。(只有使用exec()或test()方法才会填入,否则为0)
multiLine 返回创建RegExp对象实例时指定的multiLine标志(m)的状态。如果创建RegExp对象实例时设置了m标志,该属性返回True,否则返回False,默认值为False。
source 返回创建RegExp对象实例时指定的表达式文本字符串。

参考

  1. 司徒正美 javascript正则表达式
  2. MDN 正则表达式
  3. 饥人谷 课件