RegExp 构造函数
在 ES5 中,RegExp 构造函数的参数有两种情况
- 参数是字符串,第二个参数标识正则表达式的修饰符
- 参数是正则表达式,返回一个原正则表达式的拷贝,此时不允许在使用第二个参数添加修饰符,会报错
ES6 针对第二种情况作了改变:当第一个参数为整个表达式时,允许使用第二个参数指定修饰符,同时会忽略原有正则表达式的修饰符,只使用新指定的修饰符
u 修饰符
ES6 对正则表达式添加了 u 修饰符,含义为「Unicode模式」,用来正确处理大于\uFFFF的Unicode字符
/^\uD83D/u.test('\uD83D\uDC2A') // false
/^\uD83D/.test('\uD83D\uDC2A') // true
y 修饰符
ES6 还添加了 y 修饰符,叫做「粘连」修饰符
y 修饰符和 g 修饰符类似,都是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。不同的是,g 修饰符只要剩余位置中存在匹配即可,而 y 修饰符需要确保匹配必须从剩余的第一个位置开始
var s = 'aaa_aa_a'
var r1 = /a+/g
var r2 = /a+/y
r1.exec(s) // ['aaa']
r2.exec(s) // ['aaa']
r1.exec(s) // ['aa']
r2.exec(s) // null
第一次执行结果相同,都是从第一个位置开始匹配,而第二次执行,从剩余字符串 _aa_a 中进行匹配,g 修饰符没有位置要求,得到结果,y 修饰符从头开始,没有匹配到结果,所以返回 null
sticky 属性
与 y 修饰符相匹配,表示是否设置了 y 修饰符
var r = /hello\d/y
r.sticky // true
flags 属性
ES6 新增 flags 属性,用于返回正则表达式的修饰符
// ES5 的 source 属性
// 返回正则表达式的正文
/abc/ig.source // 'abc'
// ES6 的 flags 属性
// 返回正则表达式的修饰符
/abc/ig.flags // 'gi'
s 修饰符:dotAll 模式
正则表达式中,点(.)是一个特殊字符,它代表任意的单个字符,但是行终止符除外
- U+000A 换行符(\n)
- U+000D 回车符(\r)
- U+2028 行分隔符
- U+2029 段分隔符
/foo.bar/.test('foo\nbar') // false
因为点(.)不匹配 \n ,所以返回 false
/foo.bar/s.test('foo\nbar') // true
后行断言
JavaScript 语言的正则表达式只支持先行断言和先行否定断言,不支持后行断言和后行否定断言
- 先行断言:x 只有在 y 前面才匹配,必须写成
/x(?=y)/的形式,比如,只匹配百分号之前的数字 - 先行否定断言:x 只有不在 y 前面才匹配,必须写成
/x(?!y)/的形式,比如,只匹配不在百分号之前的数字 - 后行断言:x 只有在 y 后面才匹配,必须写成
/(?<=y)x/的形式,比如,只匹配美元符号之后的数字 - 后行否定断言:x 只有不在 y 后面才匹配,必须写成
/(?<!y)x/的形式,比如,只匹配不在美元符号后面的数字
具名组匹配
const RE_DATE = /(\d{4}-(\d{2})-(\d{2}))/
const matchObj = RE_DATE.exec('1999-12-31')
const year = matchObj[1] // 1999
const month = matchObj[2] // 12
const day = matchObj[3] // 31
组匹配存在的问题
- 每一组的匹配含义不容易看出来
- 只能用数字序号引用
- 如果顺序变了,引用的时候必须修改序号
使用「具名组匹配」
const RE_DATE = /(?<year>\d{4}-(?<month>\d{2})-(?<day>\d{2}))/
const matchObj = RE_DATE.exec('1999-12-31')
const year = matchObj.groups.year // 1999
const month = matchObj.groups.month // 12
const day = matchObj.groups.day // 31
有了具名组匹配之后,就可以使用解构赋值,直接从匹配结果上为变量赋值,同时,可以使用 $<组名> 引用具名组
const re = /(?<year>\d{4}-(?<month>\d{2})-(?<day>\d{2}))/
'2015-01-02'.replace(re, '$<day>/$<month>/$<year>') // 02/01/2015
还可以通过 \k<组名> 的写法在正则表达式内部引用某个具名组匹配
const RE_TWICE = /^(?<word>[a-z]+)!\k<word>$/
RE_TWICE.test('abc!abc') // true
RE_TWICE.test('abc!ab') // false
数字引用 (\1) 依然有效,两种引用语法还可以同时使用