正则的扩展
原书作者:阮一峰
原书地址:ECMASript 6入门
- RegExp构造函数
- 修饰符
- 后行断言(提案)
1. RegExp构造函数
- 两种形式
var regex = new RegExp('xyz', 'i');
// 等价于
var regex = /xyz/i;
// 参数是字符串,第二个参数为正则表达式的修饰符
var regex = new RegExp(/xyz/i);
// 等价于
var regex = /xyz/i;
// 参数是一个正则表达式的情况
- ES5 不支持第二个参数形式
var regex = new RegExp(/xyz/, 'i');
// Uncaught TypeError: Cannot supply flags
new RegExp(/abc/ig, 'i').flags
// "i"
// i替换了原ig为新的修饰符
2. 修饰符
ES6新增的flags属性返回对应的修饰符
// ES5 的 source 属性
// 返回正则表达式的正文
/abc/ig.source
// "abc"
// ES6 的 flags 属性
// 返回正则表达式的修饰符
/abc/ig.flags
// 'gi'
- u修饰符
ES6 对正则表达式添加了u修饰符,含义为“Unicode模式”,
用来正确处理大于\uFFFF的 Unicode 字符。
/^\uD83D/u.test('\uD83D\uDC2A') // false
/^\uD83D/.test('\uD83D\uDC2A') // true
// \uD83D\uDC2A是一个四个字节的 UTF-16 编码,代表一个字符
// 不加入u时,会错误认为是两个字符
- u修饰符使用场景
- 点字符(匹配码点大于0xFFFF需要使用u修饰符)
var s = '𠮷'; /^.$/.test(s) // false /^.$/u.test(s) // true
- unicode字符表示法(识别大括号unicode需要加上u)
/\u{61}/.test('a') // false /\u{61}/u.test('a') // true /\u{20BB7}/u.test('𠮷') // true
- 量词(使用unicode后,所有量词都会识别码点大于0xFFFF的字符)
/a{2}/.test('aa') // true /a{2}/u.test('aa') // true /𠮷{2}/.test('𠮷𠮷') // false /𠮷{2}/u.test('𠮷𠮷') // true
- 预定义模式
/^\S$/.test('𠮷') // false /^\S$/u.test('𠮷') // true // ^\S为不是空格的其他字符
- y修饰符
ES6 还为正则表达式添加了y修饰符,叫做“粘连”(sticky)修饰符;
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
- y修饰符应用场景
- split方法,原字符需要以分隔符开头,如果匹配成功,第一个成员为空字符串
// 没有找到匹配 'x##'.split(/#/y) // [ 'x##' ] // 找到两个匹配 '##x'.split(/#/y) // [ '', '', 'x' ]
- match方法,只能返回第一个匹配,返回所有结果需要配合g
'a1a2a3'.match(/a\d/y) // ["a1"] 'a1a2a3'.match(/a\d/gy) // ["a1", "a2", "a3"]
- 检测非法字符
const TOKEN_Y = /\s*(\+|[0-9]+)\s*/y; const TOKEN_G = /\s*(\+|[0-9]+)\s*/g; function tokenize(TOKEN_REGEX, str) { let result = []; let match; while (match = TOKEN_REGEX.exec(str)) { result.push(match[1]); } return result; } tokenize(TOKEN_Y, '3 + 4') // [ '3', '+', '4' ] tokenize(TOKEN_G, '3 + 4') // [ '3', '+', '4' ] // 无异常字符时,二者结果一致 tokenize(TOKEN_Y, '3x + 4') // [ '3' ] tokenize(TOKEN_G, '3x + 4') // [ '3', '+', '4' ] // 出现异常字符x时,二者结果不一致
- sticky属性(用于检测是否设置了y修饰符)
var r = /hello\d/y; r.sticky // true
- s修饰符(提案)
正则表达式中,"."是一个特殊的字符,代表任意字符,终止符除外
以下为四种终止符
U+000A 换行符(\n)
U+000D 回车符(\r)
U+2028 行分隔符(line separator)
U+2029 段分隔符(paragraph separator)
/foo.bar/.test('foo\nbar')
// false
// .不能匹配\n
/foo[^]bar/.test('foo\nbar')
// true
// 变通的写法如上所示
提案中,/s使得.可以匹配任意字符
这被称为dotAll模式,dot即.可以匹配任意字符
/foo.bar/s.test('foo\nbar') // true
3. 后行断言(提案)
(ES5 仅支持先行断言和先行否定断言)
”先行断言“指的是,x只有在y前面才匹配,必须写成/x(?=y)/;
先行否定断言“指的是,x只有不在y前面才匹配,必须写成/x(?!y)/;
/\d+(?=%)/.exec('100% of US presidents have been male') // ["100"]
/\d+(?!%)/.exec('that’s all 44 of them') // ["44"]
“后行断言”正好与“先行断言”相反,x只有在y后面才匹配,必须写成/(?<=y)x/;
”后行否定断言“则与”先行否定断言“相反,x只有不在y后面才匹配,必须写成/(?<!y)x/
/(?<=\$)\d+/.exec('Benjamin Franklin is on the $100 bill') // ["100"]
/(?<!\$)\d+/.exec('it’s is worth about €90') // ["90"]