前言
本章介绍正则的扩大。有些不罕用的常识理解即可。
本章原文链接:正则的扩大
RegExp 构造函数
从 ES6 开始,如果RegExp
构造函数第一个参数是一个正则对象,并且第二个标记存在且为标记参数,将不再抛出 TypeError
,将应用这些参数创立一个新的正则表达式。原有的正则表达式修饰符将被疏忽
const flag = new RegExp(/[0-9]/ig, 'i').flags; // 原有修饰符卫 ig ,被 i 给代替了console.log(flag); // i
字符串无关正则表达式
ES6将之前字符串上的四个对于正则表达式的办法全副更改为RegExp
的实例办法,所以当初所有与正则表达式无关的办法,全副定义在RegExp
对象上。
String.prototype.match
调用RegExp.prototype[Symbol.match]
String.prototype.replace
调用RegExp.prototype[Symbol.replace]
String.prototype.search
调用RegExp.prototype[Symbol.search]
String.prototype.split
调用RegExp.prototype[Symbol.split]
flags 属性
RegExp.prototype.flags
属性 是ES6新增属性,会返回正则表达式的修饰符。
const SAMPLEREG = /abc/ig;console.log(SAMPLEREG.flags); // gi
u 修饰符
在ES6中新增了 u
修饰符,示意应用Unicode
码的模式进行匹配。解决大于\uFFFF
的 Unicode
字符
留神
一旦加上u
润饰符号,就会批改上面这些正则表达式的行为。
- 点字符
对于码点大于0xFFFF
的 Unicode
字符,点字符不能辨认,必须加上u
修饰符。
**Unicode**
字符表示法
新增了应用大括号示意 Unicode
字符,这种表示法在正则表达式中必须加上u
修饰符,能力辨认当中的大括号,否则会被解读为量词。
- 量词
应用u
修饰符后,所有量词都会正确识别码点大于0xFFFF
的 Unicode
字符。
- 预约义模式
u
修饰符也影响到预约义模式,是否正确识别码点大于0xFFFF的 Unicode 字符。
i
修饰符
有些 Unicode
字符的编码不同,然而字型很相近,比方,\u004B
与\u212A
都是大写的K
- 本义
没有u
修饰符的状况下,正则中没有定义的本义(如逗号的本义\,
)有效,而在u模式会报错。
unicode 属性
RegExp.prototype.unicode
属性表明正则表达式带有"u
" 标记。 unicode
是正则表达式独立实例的只读属性。
const SAMPLEREG = /abc/u;console.log(SAMPLEREG.flags); // uconsole.log(SAMPLEREG.unicode); // true
Unicode 属性类
**Unicode property escapes**
ES2018 引入了一种新的类的写法\p{...}
和\`P{...},用于解决 JavaScript 没有强无效的形式用匹配出不同文字问题。容许正则表达式匹配合乎
Unicode` 某种属性的所有字符。
\p{Unicode属性名=Unicode属性值}// 对于某些属性,能够只写属性名,或者只写属性值。\p{Unicode属性值}\p{Unicode属性名}// \P 为 \p 取反\P{Unicode属性值}\P{Unicode属性名}
留神:
这两品种只对 Unicode
无效,所以应用的时候肯定要加上u
修饰符。\P{…}
是\p{…}
的反向匹配,即匹配不满足条件的字符。
const SAMPLEREG = /\p{Script=Greek}/u;SAMPLEREG.test(''); // true
y 修饰符
y 修饰符的作用
在ES6中新增了 y
修饰符,示意执行“粘性(sticky)”搜寻,匹配从指标字符串的以后地位开始。
y
修饰符与g
修饰符类似,都是全局匹配,后一次匹配从上一次匹配胜利的下一个地位开始。
区别是:g
修饰符只有残余地位中存在匹配即可;而y
修饰符必须从残余的第一个地位开始匹配。
// y修饰符与g修饰符的区别const SAMPLE = 'abcdabcd';const SAMPLEREG1 = /abcd/g;const SAMPLEREG2 = /abcda/y;console.log(SAMPLEREG1.test(SAMPLE)); // trueconsole.log(SAMPLEREG2.test(SAMPLE)); // trueconsole.log(SAMPLEREG1.test(SAMPLE)); // trueconsole.log(SAMPLEREG2.test(SAMPLE)); // false
留神
实际上,y
润饰符号隐含了头部匹配的标记^
。
const SAMPLEREGGY = /ab/gy;const SAMPLEREGY = /ab/y;let sample1 = 'ababcabcd'.replace(SAMPLEREGGY, '-'); let sample2 = 'ababcabcd'.replace(SAMPLEREGY, '-');// 最初一个ab因为不是呈现在下一次匹配的头部,所以不会被替换。console.log(sample1);// 只能返回第一个匹配,必须与g修饰符联用,能力返回所有匹配。console.log(sample2);
sticky 属性
RegExp.prototype.sticky
示意是否设置了y
修饰符。sticky
是正则表达式对象的只读属性。
const SAMPLEREG = /a/gy;console.log(SAMPLEREG.sticky); // true
s 修饰符
ES2018 引入s
修饰符,使得.
能够匹配任意单个字符。包含行终止符(line terminator character)。
行终止符
所谓行终止符,就是该字符示意一行的终结。以下四个字符属于“行终止符”。
U+000A
换行符(\n
)U+000D
回车符(\r
)U+2028
行分隔符(line separator
)U+2029
段分隔符(paragraph separator
)
const SAMPLEREG = /ab.cd/s;console.log(SAMPLEREG.test('ab\ncd') ); // true
dotAll
下面这种状况被称为**dotAll**
模式,即点(dot)代表所有字符。正则表达式还引入了一个**dotAll**
属性dotAll
属性返回一个布尔值,表明是否在正则表达式中一起应用"s
"修饰符。dotAll
是一个只读的属性,属于单个正则表达式实例。
const SAMPLEREG = /ab.cd/s; const sample = SAMPLEREG.test('ab\ncd'); console.log(SAMPLEREG.flags); // s console.log(SAMPLEREG.dotAll); // true
后行断言
ES2018 引入后行断言,V8 引擎 4.9 版(Chrome 62)曾经反对。
后行断言
x
只有在y
后面才匹配,必须写成/x(?=y)/
。
比方,只匹配百分号之前的数字,要写成/\d+(?=%)/
。后行否定断言
,x
只有不在y
后面才匹配,必须写成/x(?!y)/
。
比方,只匹配不在百分号之前的数字,要写成/\d+(?!%)/
。后行断言
正好与后行断言
相同,x
只有在y
前面才匹配,必须写成/(?<=y)x/
。
比方,只匹配美元符号之后的数字,要写成/(?<=\$)\d+/
。后行否定断言
则与后行否定断言
相同,x
只有不在y
前面才匹配,必须写成/(?<!y)x/
。
比方,只匹配不在美元符号前面的数字,要写成/(?<!\$)\d+/
。
后行断言须要先匹配/(?<=y)x/
的x
,而后再回到右边,匹配y
的局部。程序为先右后左,
// 后行断言const sample1 = /\d+(?=%)/.exec('100% of US presidents have been male');// 后行否定断言const sample2 = /\d+(?!%)/.exec('that’s all 44 of them');console.log(sample1); // 100console.log(sample2); // 44// 后行断言const sample3 = /(?<=\$)\d+/.exec('Benjamin Franklin is on the $100 bill');// 后行否定断言const sample4 = /(?<!\$)\d+/.exec('it’s is worth about 90');console.log(sample3); // 100console.log(sample4); // 90
组匹配
正则表达式的括号示意分组匹配,括号中的模式能够用来匹配分组的内容。
ES2018 引入了具名组匹配(Named Capture Groups),容许为每一个组匹配指定一个名字,既便于浏览代码,又便于援用。
具名组匹配在圆括号外部,模式的头部增加“问号 + 尖括号 + 组名”(?<year>)
,而后就能够在exec
办法返回后果的groups
属性上援用该组名。同时,数字序号仍然无效。
const sampleUsers = `姓刘名备字玄德姓关名羽字云长姓张名飞字翼德`;const SAMPLEREG = /姓(?<surnames>.+)名(?<name>.+)字(?<word>.+)/g;let result = SAMPLEREG.exec(sampleUsers);do { console.log(`${result.groups.surnames}${result.groups.name}${result.groups.surnames}${result.groups.word}`);} while ((result = SAMPLEREG.exec(sampleUsers)) !== null);/** 刘备刘玄德* 关羽关云长* 张飞张翼德*/
下面的代码中:?<xxx>
的作用就是为这个匹配定义一个组名,在匹配的groups
属性中能够查看到匹配的组名,这里能够应用解构赋值间接从匹配后果上为变量赋值。
留神 : 如果要在正则表达式外部援用某个具名组匹配,能够应用\k<组名>
的写法
matchAll()
ES2020 减少了String.prototype.matchAll()
办法,能够一次性取出所有匹配。不过,它返回的是一个遍历器/迭代器(Iterator
),而不是数组。
const string = 'sample1sample2sample3';const regex = /sample/g;for (const match of string.matchAll(regex)) { console.log(match);}// 遍历输入/*['sample', index: 0, input: 'sample1sample2sample3', groups: undefined]['sample', index: 7, input: 'sample1sample2sample3', groups: undefined]['sample', index: 14, input: 'sample1sample2sample3', groups: undefined]*/