ECMAScript 6学习笔记(三)正则的扩展

正则的扩展

  • 1.RegExp 构造函数
    ES6 改变了ES5 不允许此时使用第二个参数添加修饰符这种行为,如果RegExp构造函数第一个参数是一个正则对象,那么可以使用第二个参数指定修饰符。而且,返回的正则表达式会忽略原有的正则表达式的修饰符,只使用新指定的修饰符。

  • 2.字符串的正则方法
    字符串对象共有 4 个方法,可以使用正则表达式:match()、replace()、search()和split()。
    ES6 将这 4 个方法,在语言内部全部调用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]


  • 3.u 修饰符
    ES6 对正则表达式添加了u修饰符,含义为“Unicode 模式”,用来正确处理大于\uFFFF的 Unicode 字符。也就是说,会正确处理四个字节的 UTF-16 编码。

一旦加上u修饰符号,就会修改下面这些正则表达式的行为。使其能够识别码点大于0xFFFF的 Unicode 字符
(1)点字符
(2)Unicode 字符表示法
ES6 新增了使用大括号表示 Unicode 字符,这种表示法在正则表达式中必须加上u修饰符,才能识别当中的大括号,否则会被解读为量词。
(3)量词
(4)预定义模式
(5)i 修饰符


  • 4.y 修饰符
    ES6 还为正则表达式添加了y修饰符,叫做“粘连”(sticky)修饰符。
    (1)y修饰符的作用与g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。不同之处在于,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始,这也就是“粘连”的涵义。
    (2)y修饰符的设计本意,就是让头部匹配的标志^在全局匹配中都有效。
    (3)单单一个y修饰符对match方法,只能返回第一个匹配,必须与g修饰符联用,才能返回所有匹配。
    (4)y修饰符的一个应用,是从字符串提取 token(词元),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

  • 5.sticky 属性
    与y修饰符相匹配,ES6 的正则对象多了sticky属性,表示是否设置了y修饰符。返回true 或者false

  • 6.flags 属性
    ES6 为正则表达式新增了flags属性,会返回正则表达式的修饰符

  • 7.s 修饰符:dotAll 模式
    正则表达式中,点(.)是一个特殊字符,代表任意的单个字符,但是行终止符除外。
/foo.bar/.test('foo\nbar')
// false
//.不能匹配\n

const re = /foo.bar/s;
re.test('foo\nbar') // true    因此还引入了dotAll属性,返回一个布尔值,表示该正则表达式是否处在dotAll模式中
re.dotAll // true

所以现在引入/s修饰符,使得.可以匹配任意单个字符。这被称为dotAll模式,即点(dot)代表一切字符
/s修饰符和多行修饰符/m不冲突,两者一起使用的情况下,.匹配所有字符,而^和$匹配每一行的行首和行尾。


  • 8.后行断言
    (1)”先行断言“指的是,x只有在y前面才匹配,必须写成/x(?=y)/。比如,只匹配百分号之前的数字,要写成/\d+(?=%)/。
    (2)”先行否定断言“指的是,x只有不在y前面才匹配,必须写成/x(?!y)/。比如,只匹配不在百分号之前的数字,要写成/\d+(?!%)/。
    (3)“后行断言”正好与“先行断言”相反,x只有在y后面才匹配,必须写成/(?<=y)x/。比如,只匹配美元符号之后的数字,要写成/(?<=$)\d+/。
    (4)”后行否定断言“则与”先行否定断言“相反,x只有不在y后面才匹配,必须写成 /(?< ! y)x/。比如,只匹配不在美元符号后面的数字,要写成/(?< !$)\d+/。
/(?<=(\d+)(\d+))$/.exec('1053') // ["", "1", "053"]
/^(\d+)(\d+)$/.exec('1053') // ["1053", "105", "3"]

// "没有后行断言时,第一个括号是贪婪模式,第二个括号只能捕获一个字符,所以结果是105和3。而后行断言时,由于执行顺序是从右到左,第二个括号是贪婪模式,第一个括号只能捕获一个字符,所以结果是1和053。


/(?<=(o)d\1)r/.exec('hodor')  // null
/(?<=\1d(o))r/.exec('hodor')  // ["r", "o"]
//其次,"后行断言"的反斜杠引用,也与通常的顺序相反,必须放在对应的那个括号之前

  • 9.Unicode 属性类
    引入了一种新的类的写法\p{…}和\P{…},允许正则表达式匹配符合 Unicode 某种属性的所有字符。
const regexGreekSymbol = /\p{Script=Greek}/u;
regexGreekSymbol.test('π') // true
//指定匹配一个希腊文字母,所以匹配π成功。

注意,这两种类只对 Unicode 有效,所以使用的时候一定要加上u修饰符。如果不加u修饰符,正则表达式使用\p和\P会报错
\p{Number}甚至能匹配罗马数字

// 匹配所有数字
const regex = /^\p{Number}+$/u;
regex.test('²³¹¼½¾') // true
regex.test('㉛㉜㉝') // true
regex.test('ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ') // true

  • 10.具名组匹配
    正则表达式使用圆括号进行组匹配。但是每一组的匹配含义不容易看出来,顺序容易变
const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;
//使用exec方法,就可以将这三组匹配结果提取出来。
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj[1]; // 1999
const month = matchObj[2]; // 12
const day = matchObj[3]; // 31

现在有一个“具名组匹配”(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

在圆括号内部,模式的头部添加“问号 + 尖括号 + 组名”(?),然后就可以在exec方法返回结果的groups属性上引用该组名。同时,数字序号(matchObj[1])依然有效。


  • 11.解构赋值和替换
    (1)有了具名组匹配以后,可以使用解构赋值直接从匹配结果上为变量赋值。
let {groups: {one, two}} = /^(?<one>.*):(?<two>.*)$/u.exec('foo:bar');
one  // foo
two  // bar

(2)字符串替换时,使用$<组名>引用具名组

let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;

'2015-01-02'.replace(re, '$<day>/$<month>/$<year>')
// '02/01/2015'

(3)replace方法的第二个参数也可以是函数,该函数的参数序列如下

'2015-01-02'.replace(re, (
   matched, // 整个匹配结果 2015-01-02
   capture1, // 第一个组匹配 2015
   capture2, // 第二个组匹配 01
   capture3, // 第三个组匹配 02
   position, // 匹配开始的位置 0
   S, // 原字符串 2015-01-02
   groups // 具名组构成的一个对象 {year, month, day}
 ) => {
 let {day, month, year} = args[args.length - 1];
 return `${day}/${month}/${year}`;
});

具名组匹配在原来的基础上,新增了最后一个函数参数:具名组构成的一个对象。函数内部可以直接对这个对象进行解构赋值


  • 12.引用

如果要在正则表达式内部引用某个“具名组匹配”,可以使用\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

这两种引用语法还可以同时使用。

const RE_TWICE = /^(?<word>[a-z]+)!\k<word>!\1$/;
RE_TWICE.test('abc!abc!abc') // true
RE_TWICE.test('abc!abc!ab') // false

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值