ES6第六章
- EegExp构造函数
第一种情况是: 参数是字符串,这时第二个参数表示正则表达式的修饰符(flag)。
var regex = new RegExp('xyz', 'i'); // 等价于 var regex = /xyz/i;
第二种情况是,参数是一个正则表示式,这时会返回一个原有正则表达式的拷贝。在ES5中当第一个参数是正则表达式时,不支持第二个参数
如果RegExp构造函数第一个参数是一个正则对象,那么可以使用第二个参数指定修饰符。而且会忽略原有的正则表达式的修饰符,只使用新指定的修饰符。 - 字符串的正则方法
match()、replace()、search()和split()ES6 将这 4 个方法,在语言内部全部调用RegExp的实例方法
- u 修饰符
对于码点\uFFFF的字符用u后缀才能正确识别。例如: /^\uD83D/u.test(’\uD83D\uDC2A’) // false
/^\uD83D/.test(’\uD83D\uDC2A’) // true`- Unicode 字符表示法
正则表达式中必须加上u修饰符,才能识别当中的大括号,否则会被解读为量词。/\u{61}/.test('a') // false /\u{61}/u.test('a') // true
- 预定义模式
u修饰符也影响到预定义模式,能否正确识别码点大于0xFFFF的 Unicode 字符。/^\S$/.test('𠮷') // false /^\S$/u.test('𠮷') // true
- i 修饰符
i 修饰符用于执行对大小写不敏感的匹配/[a-z]/i.test('\u212A') // false /[a-z]/iu.test('\u212A') // true
- 转义
没有u修饰符的情况下,正则中没有定义的转义(如逗号的转义,)无效,而在u模式会报错。/\,/ // /\,/ /\,/u // 报错
- Unicode 字符表示法
- RegExp.prototype.unicode属性
正则实例对象新增unicode属性,表示是否设置了u修饰符 - y 修饰符
- y修饰符的作用与g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。不同之处在于,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始。
事实上,y修饰符号隐含了头部匹配的标志^。var s = 'aaa_aa_a'; var r1 = /a+/g; var r2 = /a+/y; r1.exec(s) // ["aaa"] 剩余字符串 ”_aa_a“ r2.exec(s) // ["aaa"] 剩余字符串 ”_aa_a“ r1.exec(s) // ["aa"] 剩余字符串中全局匹配 r2.exec(s) // null 从第一个字符开赛开始匹配
const TOKEN_Y = /\s*(\+|[0-9]+)\s*/y; const TOKEN_G = /\s*(\+|[0-9]+)\s*/g; tokenize(TOKEN_Y, '3x + 4') // [ '3' ] tokenize(TOKEN_G, '3x + 4') // [ '3', '+', '4' ] g修饰符会忽略非法字符 function tokenize(TOKEN_REGEX, str) { let result = []; let match; while (match = TOKEN_REGEX.exec(str)) { result.push(match[1]); } return result; }
- y修饰符的作用与g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。不同之处在于,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始。
- RegExp.prototype.sticky 属性
表示是否设置了y修饰var r = /hello\d/y; r.sticky // true
- RegExp.prototype.flags 属性
返回正则表达式的修饰符/abc/ig.source // "abc" ES5 /abc/ig.flags // 'gi' ES6
- s 修饰符:dotAll 模式
(.)是一个特殊字符,可以代表任意的单个字符,但是有两个例外。一个是四个字节的 UTF-16 字符,这个可以用u修饰符解决;另一个是行终止符(该字符表示一行的终结)U+000A 换行符(\n),U+000D 回车符(\r),U+2028 行分隔符(line separator),U+2029 段分隔符(paragraph separator)
dotAll属性,返回一个布尔值,表示该正则表达式是否处在dotAll模式。/foo.bar/.test('foo\nbar') // false /foo[^]bar/.test('foo\nbar') // true /foo.bar/s.test('foo\nbar') // true
const re = /foo.bar/s; // 另一种写法 // const re = new RegExp('foo.bar', 's'); re.test('foo\nbar') // true re.dotAll // true re.flags // 's'
- 后行断言
-
JavaScript 语言的正则表达式,只支持先行断言(lookahead)和先行否定断言(negative lookahead),不支持后行断言(lookbehind)和后行否定断言(negative lookbehind)。ES2018 引入后行断言,V8 引擎 4.9 版(Chrome 62)已经支持。
- “先行断言”指的是,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/。
“后行断言”的实现,需要先匹配/(?<=y)x/的x,然后再回到左边,匹配y的部分。这种“先右后左”的执行顺序,与所有其他正则操作相反,导致了一些不符合预期的行为。/(?<=\$)\d+/.exec('Benjamin Franklin is on the $100 bill') // ["100"] /(?<!\$)\d+/.exec('it’s is worth about €90') // ["90"]
“后行断言”的反斜杠引用,也与通常的顺序相反,必须放在对应的那个括号之前。/(?<=(\d+)(\d+))$/.exec('1053') // ["", "1", "053"] /^(\d+)(\d+)$/.exec('1053') // ["1053", "105", "3"]
/(?<=(o)d\1)r/.exec('hodor') // null /(?<=\1d(o))r/.exec('hodor') // ["r", "o"] 反斜杠引用(\1)必须放在()前面才可以
-
- Unicode 属性类
ES2018 引入了一种新的类的写法\p{…}和\P{…},允许正则表达式匹配符合 Unicode 某种属性的所有字符。
\p{UnicodePropertyName=UnicodePropertyValue} //Unicode 属性类要指定属性名和属性值。 const regexGreekSymbol = /\p{Script=Greek}/u; //匹配一个希腊字母 regexGreekSymbol.test('π') // true \P{…}是\p{…}的反向匹配,即匹配不满足条件的字符。 // 匹配所有数字 const regex = /^\p{Number}+$/u; regex.test('²³¹¼½¾') // true regex.test('㉛㉜㉝') // true regex.test('ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ') // true // 匹配所有空格 \p{White_Space} // 匹配 Emoji /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu
- 具名组匹配
-
ES2018 引入了具名组匹配(Named Capture Groups),允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用。
const RE_DATE = /(?\d{4})-(?\d{2})-(?\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
-
- 解构赋值和替换
- 可以使用解构赋值直接从匹配结果上为变量赋值
let {groups: {one, two}} = /^(?<one>.*):(?<two>.*)$/u.exec('foo:bar'); one // foo two // bar
- 可以使用解构赋值直接从匹配结果上为变量赋值
- 引用
- 如果要在正则表达式内部引用某个“具名组匹配”,可以使用\k<组名>的写法。
const RE_TWICE = /^(?<word>[a-z]+)!\k<word>$/; RE_TWICE.test('abc!abc') // true RE_TWICE.test('abc!ab') // false
- 如果要在正则表达式内部引用某个“具名组匹配”,可以使用\k<组名>的写法。
- 正则匹配索引
-
由于正则匹配结果的开始位置和结束位置,目前获取并不是很方便。正则实例的exec()方法,返回结果有一个index属性,可以获取整个匹配结果的开始位置,但是如果包含组匹配,每个组匹配的开始位置,很难拿到。
第三阶段提案,为exec()方法的返回结果加上indices属性,在这个属性上面可以拿到匹配的开始位置和结束位置。
如果正则表达式包含组匹配,那么indices属性对应的数组就会包含多个成员,提供每个组匹配的开始位置和结束位置。const text = 'zabbcdef'; const re = /ab/; const result = re.exec(text); result.index // 1 result.indices // [ [1, 3] ]
如果正则表达式包含具名组匹配,indices属性数组还会有一个groups属性。该属性是一个对象,可以从该对象获取具名组匹配的开始位置和结束位置。const text = 'zabbcdef'; const re = /ab+(cd)/; const result = re.exec(text); result.indices // [ [ 1, 6 ], [ 4, 6 ] ]
如果获取组匹配不成功,indices属性数组的对应成员则为undefined,indices.groups属性对象的对应成员也是undefined。const text = 'zabbcdef'; const re = /ab+(?<Z>cd)/; const result = re.exec(text); result.indices.groups // { Z: [ 4, 6 ] }
const text = 'zabbcdef'; const re = /ab+(?<Z>ce)?/; const result = re.exec(text); result.indices[1] // undefined result.indices.groups['Z'] // undefined
-
- String.prototype.matchAll()
- String.prototype.matchAll()方法,可以一次性取出所有匹配。不过,它返回的是一个遍历器(Iterator),而不是数组。
const string = 'test1test2test3'; const regex = /t(e)(st(\d?))/g; for (const match of string.matchAll(regex)) { console.log(match); } // ["test1", "e", "st1", "1", index: 0, input: "test1test2test3"] // ["test2", "e", "st2", "2", index: 5, input: "test1test2test3"] // ["test3", "e", "st3", "3", index: 10, input: "test1test2test3"]