# javascript正则表达式<sup>谢忠阳</sup>
### 前言
正则表达式一直是困扰很多程序员的一门技术。前端面试过程中多少会被问到一些简单的正则表达式,但大部分应试者都会说:正则不是很了解,遇到问题都会直接搜索复制粘贴。我觉得作为程序开发者,有必要好好了解一下正则,因为很多问题都可以通过一条简单的正则表达式解决,避免写大量脚本去实现。希望这次分享能帮助大家掌握基础的正则,揭开正则表达式各种符号的神秘面纱,从此走上正则大神之路!
### 什么是正则表达式
来源于Perl的正则表达式是一门简单语言的语法规范,主要应用于字符串的信息实现查找、替换和提取的`技巧`操作。
这里强调是技巧操作,其处理字符串的速度是相当慢的,远不如indexOf、lastIndexOf、includes的速度快,所以勿滥用!但又必须学会,有些需求还非正则解决不了呢。
> 正则表达式的核心是:要么匹配`字符`,要么匹配`位置`!<br/>
> 正则:匹配`字符`,匹配`位置`!<br/>
> 正则:`字符` `位置`!
### 常见正则问题:
- 将123456789转化为`123,456,789`
- 验证密码必须8位以上,以字母开头,必须含有数字、大小写字母
- 剔除字符串中所有html的标签
## 正则表达式基础
### 原子(字符)
原子是正则表达式的最基本组成单位,而且必须至少要包含一个原子。
| 正则 | 意思 | 说明 |
| ------------ |:-------------| -----|
|. |匹配除换行符以外的任意字符|加/s表示所有字符|
|\d |匹配一个数字字符|等价于 \[0-9]|
|\D |匹配一个非数字字符|等价于 \[^0-9]|
|\w |匹配包括下划线的任何单词字符|等价于\[A-Za-z0-9_]|
|\W |匹配任何非单词字符|等价于\[^A-Za-z0-9_]|
|\s |匹配任何空白字符,包括空格、制表符、换页符等等|等价于\[\f\n\r\t\v\u000B\u0020\u00A0\u2028\u2029]|
|\S |匹配任何非空白字符|等价于 \[^ \f\n\r\t\v]|
|\n |匹配一个换行符|等价于 \x0a 和 \cJ|
|\f |匹配一个换页符|等价于 \x0c 和 \cL|
|\r |匹配一个回车符|等价于 \x0d 和 \cM|
|\t |匹配一个制表符|等价于 \x09 和 \cI|
|\v |匹配一个垂直制表符|等价于 \x0b 和 \cK|
|\xxx |匹配八进制规定的ASCII编码字符|比如\[0-9]可写成\[\48-\57]|
|\xdd |匹配十六进制规定的ASCII编码字符|比如\[0-9]可写成\[\x30-\x39]|
|\uxxxx |匹配十六进制规定的Unicode字符|比如\[0-9]可写成\[\u0030-\u0039]|
|[A-Za-z]|匹配所有大小写字母| 等价于 /\[a-z]/i |
|[^a-z]|匹配非字母|匹配指定范围以外的字符|
|[a-f1-5]|自定义原子表又称`范围集合类`| |
#### 范围集合类
[abc],表示a或者b或者c中的任意一个字符;
[a-z]、[A-Z]、[0-9],表示小写字母,大写字母,0到9的数字;
[^a-z]、[^A-Z]、[^0-9],表示非小写字母,非大写字母,非0到9的数字;
更多参见基本多语言面(Basic Multilingual Plane,BMP)详细信息[基本多文种平面](http://baike.baidu.com/view/628163.htm)
#### 分枝条件
`分枝条件`指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,方法是用|把不同的规则分隔开。
```js
"aababxb".replace(/a|b/g,'')
```
### 元字符
元字符是一种特殊的字符,是用来修饰原子用的,不可以单独出现;
#### 量词类
| 正则 | 说明|
|------------|-----|
|{m} |表示前面的原子必须出现m次|
|{m,}|表示前面的原子最少出现m次|
|{m,n}|m要小于n,表示前面出现的原子,最少m次,最多n次,包括m和n次|
|? |等价{0,1}表示其前面的原子可以出现0次或1次,有只能有一次,要么没有|
|+ |等价{1,}表示其前的原子可以出现1次或多次,不能没有最少要有一个|
|* |等价{0,}表示其前的原子可以出现0次、1次、或多次|
##### 贪婪和非贪婪(懒惰)匹配
当正则表达式中包含能接受重复的限定符时,通常的行为是匹配尽可能多的字符。
```js
"aababxb".match(/a.*b/);//贪婪匹配 返回aababxb
"aababxb".match(/a.*?b/);//懒惰匹配 返回aab
```
它将会匹配整个字符串。这被称为贪婪匹配。
| 代码/语法| 说明 |
| ---------|-----------|
|{n,}? |重复n次以上,但尽可能少重复|
|{n,m}? |重复n到m次,但尽可能少重复|
| ?? |重复0次或1次,但尽可能少重复|
| +? |重复1次或更多次,但尽可能少重复|
| *? |重复任意次,但尽可能少重复|
#### 边界类(位置)
位置可以理解为相邻字符之间的位置。咱们可以和空字符串进行类比, 字符的首尾、间隙都可以用空字符串进行连接。
```js
'hello' === '' + 'h' + '' + 'e' + '' + 'l' + '' + 'l' + '' + 'o' + ''
```
![](img/位置.jpg)
| 符号 | 说明|
|------------|-----|
|^ |脱字符,有m时是行的开头,无m是字符串的开始|
|$ |美元符,有m时是行的末尾,无m是字符串的结束|
|\b |单词的边界,具体讲有三点规则:①\w和\W之间的位置 ②^与\w之间的位置 ③\w与$之间的位置|
|\B |非单词的边界,与上面相反:①\w与\w之间的位置 ②\W与\W之间的位置 ③^与\W之间的位置 ④\W与$之间的位置|
```js
var regex = '666root_cloud.com'.replace(/\b/g,'❤')
```
![](img/边界.jpg)
```js
var regex = '[[666root_cloud.com]]'.replace(/\B/g,'❤')
```
![](img/非边界.jpg)
## 正则表达式应用
### 创建正则表达式
```js
var reg = /xzy/i; //推荐
var reg = new RegExp('xzy', 'i'); //用于动态变量创建
var reg = new RegExp(/xzy/i);
var reg = new RegExp(/xzy/i, 'i');//ES5不允许;ES6可以并且第二个参数指定的修饰符会覆盖前面的修饰符
var reg = eval("/xzy/i");//不建议
var reg = new Function("return /xzy/i")();//不建议
console.dir(reg)
```
### RegExp实例属性
| 属性 | flags | 说明 |
| -----------|------|-------|
| lastIndex | | 下一次匹配开始的索引,初始值为0。可读写整型属性|
| dotAll |/s| 允许`.`匹配换行符, ES7|
| flags | | 返回正则表达式的修饰符, ES6|
| global |/g| 全局搜索。匹配字符串中所有可能的字符,而不是仅匹配符合条件的第一项|
| hasIndices|/d| 为匹配子串生成开头和结尾的索引,索引通过 RegExpArray 的 indices 数组获得|
| ignoreCase|/i| 匹配文本的时候忽略大小写来进行搜索|
| multiline |/m| 多行搜索,这意味着在包含多个行的字符串中使用^和$符号时,会匹配每行的开头和结尾,而不是默认的只匹配整个字符串的开头和结尾|
| source | | 正则表达式源码文本|
| sticky |/y| 粘性搜索(ES6)。每次从lastIndex所标识的起始位置开始匹配,如果匹配失败将更新lastIndex为0;如果匹配成功将更新lastIndex为相应值,下次继续从lastIndex匹配。这里的“粘性”想表达的是只有当匹配项是连续的、相“粘连”的,搜索才会从当前下标位置继续下去,否则lastIndex归0从头开始。当 y 和 g 标志被同时使用时会省略 g 标志|
| unicode |/u| 开启Unicode功能。ES6|
- lastIndex
```js
var reg = /\d+/g
var str = '123abc'
console.log(reg.test(str)) // true
console.log(reg.lastIndex)
console.log(reg.test(str)) // false
```
- dotAll
```js
console.log(`abc
123`.match(/.+/s))
```
- global
```js
console.log(`1a2b3c`.replace(/\d+/g,'*'))
```
- flags
```js
var reg = new RegExp('a', 'sgdimyu')
console.log(reg.flags);//dgimsuy ES6规范中规定了表达式的标识按照字符顺序输出,即dgimsuy
```
- hasIndices
```js
var str = 'foo bar foo'
var reg = new RegExp('foo', 'gd')
console.log(reg.hasIndices) // true
console.log(reg.exec(str).indices[0]) // Array [0, 3]
console.log(reg.exec(str).indices[0]) // Array [8, 11]
`