@xiaoyixy
2018-11-08T17:05:53.000000Z
字数 4058
阅读 1079
Note
ES6
ECMAScript6
第一个参数为正则表达式而第二个标志参数存在时,
new RegExp(/ab+c/, 'i')
不再抛出 TypeError
/ab+c/i;
new RegExp('ab+c', 'i');
new RegExp(/ab+c/, 'i');
new RegExp(/ab+c/, 'i');
// Starting with ECMAScript 6, new RegExp(/ab+c/, 'i') no longer throws a TypeError ("can't supply flags when constructing one RegExp from another") when the first argument is a RegExp and the second flags argument is present. A new RegExp from the arguments is created instead.
Unicode; 将模式视为 Unicode 序列点的序列,用来正确处理大于 \uFFFF 的 Unicode 字符
// \uD83D\uDC2A是一个四个字节的 UTF-16 编码,代表一个字符
// ES5 不支持四个字节的 UTF-16 编码,会将其识别为两个字符
/^\uD83D/u.test('\uD83D\uDC2A') // false
/^\uD83D/.test('\uD83D\uDC2A') // true
// 1. 对于码点大于0xFFFF的 Unicode 字符,点字符(.)不能识别,必须加上 u 修饰符。
var s = '𠮷';
/^.$/.test(s) // false
/^.$/u.test(s) // true
// 2. ES6 新增了使用大括号表示 Unicode 字符,这种表示法在正则表达式中必须加上u修饰符,才能识别当中的大括号,否则会被解读为量词。
/\u{61}/.test('a') // false
/\u{61}/u.test('a') // true
/\u{20BB7}/u.test('𠮷') // true
// 3. 使用u修饰符后,所有量词都会正确识别码点大于0xFFFF的 Unicode 字符。
/a{2}/.test('aa') // true
/a{2}/u.test('aa') // true
/𠮷{2}/.test('𠮷𠮷') // false
/𠮷{2}/u.test('𠮷𠮷') // true
// 4. 预定义模式
// 下面代码的\S是预定义模式,匹配所有非空白字符。只有加了u修饰符,它才能正确匹配码点大于0xFFFF的 Unicode 字符。
/^\S$/.test('𠮷') // false
/^\S$/u.test('𠮷') // true
// 5. i 修饰符
// 有些 Unicode 字符的编码不同,但是字型很相近,比如,\u004B与\u212A都是大写的K
/[a-z]/i.test('\u212A') // false
/[a-z]/iu.test('\u212A') // true
粘性匹配; 仅匹配目标字符串中此正则表达式的 lastIndex 属性指示的索引(并且不尝试从任何后续的索引匹配)。
// g
var regex1 = RegExp('foo*','g');
var regex2 = RegExp('foo*','y');
var str1 = 'football, foosball';
var array1, array2;
while ((array1 = regex1.exec(str1)) !== null) {
console.log(`Found ${array1[0]}. Next starts at ${regex1.lastIndex}.`);
// "Found foo. Next starts at 3."
// "Found foo. Next starts at 13."
}
// y
while ((array2 = regex2.exec(str1)) !== null) {
console.log(`Found ${array2[0]}. Next starts at ${regex2.lastIndex}.`);
// "Found foo. Next starts at 3."
}
单单一个y修饰符对match方法,只能返回第一个匹配,必须与g修饰符联用,才能返回所有匹配。
'a1a2a3'.match(/a\d/y) // ["a1"]
'a1a2a3'.match(/a\d/gy) // ["a1", "a2", "a3"]
ES2018 引入s修饰符,使得.可以匹配任意单个字符。
正则表达式中,点(.)是一个特殊字符,代表任意的单个字符,但是有两个例外。一个是四个字节的 UTF-16 字符,这个可以用u修饰符解决;另一个是行终止符(line terminator character)。
/foo.bar/.test('foo\nbar') // false
/foo[^]bar/.test('foo\nbar') // true
// ES2018
/foo.bar/s.test('foo\nbar') // true
JavaScript 语言的正则表达式,只支持先行断言(lookahead)和先行否定断言(negative lookahead),不支持后行断言(lookbehind)和后行否定断言(negative lookbehind)。ES2018 引入后行断言,V8 引擎 4.9 版(Chrome 62)已经支持。
/x(?=y)/
/x(?!y)/
/(?<=y)x/
/(?<!y)x/
/\d+(?=%)/.exec('100% of US presidents have been male') // ["100"]
/\d+(?!%)/.exec('that’s all 44 of them') // ["44"]
/(?<=\$)\d+/.exec('Benjamin Franklin is on the $100 bill')
// ["100"]
/(?<!\$)\d+/.exec('it’s is worth about €90')
// ["90"]
“后行断言”的实现,需要先匹配/(?<=y)x/的x,然后再回到左边,匹配y的部分。这种“先右后左”的执行顺序,与所有其他正则操作相反,导致了一些不符合预期的行为。
/(?<=(\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"]
ES2018 引入了一种新的类的写法\p{...}和\P{...},允许正则表达式匹配符合 Unicode 某种属性的所有字符。
Unicode 属性类要指定属性名和属性值。
\p{UnicodePropertyName=UnicodePropertyValue}
对于某些属性,可以只写属性名,或者只写属性值。
\p{UnicodePropertyName}
\p{UnicodePropertyValue}
\P{…}
是 \p{…}
的反向匹配,即匹配不满足条件的字符。
注意,这两种类只对 Unicode 有效,所以使用的时候一定要加上u修饰符。如果不加u修饰符,正则表达式使用\p和\P会报错,ECMAScript 预留了这两个类。
const regexGreekSymbol = /\p{Script=Greek}/u;
regexGreekSymbol.test('π') // true
正则表达式使用圆括号进行组匹配。
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
ES2018 引入了具名组匹配(Named Capture Groups),允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用。
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
如果要在正则表达式内部引用某个“具名组匹配”,可以使用\k<组名>的写法。
const RE_TWICE = /^(?<word>[a-z]+)!\k<word>$/;
RE_TWICE.test('abc!abc') // true
RE_TWICE.test('abc!ab') // false
// 数字引用(\1)依然有效。
const RE_TWICE = /^(?<word>[a-z]+)!\1$/;
RE_TWICE.test('abc!abc') // true
RE_TWICE.test('abc!ab') // false