《ES6标准入门(第3版)》学习笔记15:chapter_5 正则的扩展(三)

这是该系列的第15篇学习笔记!
8,后行断言

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>后行断言</title>
</head>
<body>
    
    <script>
    // JavaScript语言的正则表达式只支持“先行断言”和“先行否定断言”,不支持“后行断言”和“后行否定断言”    
    // 先行断言 --> x只有在y前面才匹配,必须写成“/x(?=y)/”的形式
    //             例如,只匹配百分号之前的数字,要写成"/\d+(?=%)/"

    // 先行否定断言 --> x只有不在y前面才匹配,必须写成“/x(?!y)/”的形式
    //             例如,只匹配不在百分号之前的数字,要写成"/\d+(?!%)/"

    console.log(/\d+(?=%)/.exec('100% of US presidents have been male'));  // ['100']
    console.log(/\d+(?!%)/.exec('that is all 44 of them'));  // ['44']
    

    // 互换正则表达式,则会匹配失败
    // 另外,“先行断言”括号之中的部分(?=%)是不计入返回结果的
    console.log(/\d+(?!%)/.exec('100% of US presidents have been male'));  // ['10']
    console.log(/\d+(?=%)/.exec('that is all 44 of them'));  // null
    
    // 后行断言 --> x只有在y后面才匹配,必须写成“/(?<=y)x/”的形式
    //             例如,只匹配美元之后的数字,要写成"/(?<=\$)\d+/"

    // 后行否定断言 --> x只有不在y后面才匹配,必须写成“/(?<!y)x/”的形式
    //             例如,只匹配不在百分号之前的数字,要写成"/(?<!\$)\d+/"
    console.log(/(?<=\$)\d+/.exec('Beinge is ont the $10323.23 bill'));
    console.log(/(?<!\$)\d+/.exec("it's worth about %981212"))
    // “后行断言”括号之中的部分(?<=\$)是不计入返回结果的

    
    // “后行断言”的实现需要先匹配“/(?<=y)x/”的x,然后在回到左边匹配y的部分,这种“先右后左”的执行顺序与所有其他正则操作相反,导致了一些不符合预期的结果
    // 代码捕获两个组匹配
    console.log(/(?<=(\d+)(\d+))$/.exec('1053'));  // [ "", "1", "053"] --> 有“后行断言”,由于执行顺序是从右到左,所以第二个括号是贪婪模式,第一个括号只能捕获一个字符
    console.log(/^(\d+)(\d+)$/.exec('1053'));  // ["1053", "105", "3"] --> 没有“后行断言”,第一个括号是贪婪模式,第二个括号只能捕获一个字符
    


    // “后行断言”的反斜杠引用也与通常的顺序相反,必须放在对应的括号之前
    console.log(/(?<=(o)d\1)r/.exec('hodor'));  //  null
    console.log(/(?<=\1d(o))r/.exec('hodor'));  // ['r', 'o']
    // 上面代码中,后行断言的反斜杠引用(\1)必须放在前面才可以,放在括号后边不会得到匹配结果
    // --> 后行断言是从左到右进行扫描,发现匹配后再回过头来从右到左完成反斜杠引用


    
    </script>
</body>
</html>

9,Unicode属性类

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Unicode属性类</title>
</head>
<body>
    
    <script>
    // 【提案】引入一种新的类的写法(这两种类只对Unicode有效,所以使用的时候一定要加上u修饰符,否则,会报错)
    // \p{...} and \P{...},允许正则表达式匹配符合Unicode某种属性的所有字符
    const regexGreekSymbol = /\p{Script=Greek}/u;
    console.log(regexGreekSymbol.test('n'));
    
    // Unicode属性类要指定属性名和属性值
    // \p{Script=Greek}

    // 对于某些属性,可以只写属性名
    // \p{UnicodePropertyName}

    // \P{...}是\p{...}的反向匹配,即匹配不满足条件的字符

    // 由于Unicode的属性非常多,所以这种新类的表达能力非常强
    const regex = /^\p{Decimal_Number}+$/u;
    console.log(regex.test('1234567890123456'));  // true
    
    // \p{Number}能匹配罗马数字

    // 【end】
    
    
    
    
    </script>
</body>
</html>

10,具名组匹配

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>具名组匹配</title>
</head>
<body>
    
    <script>
    
    // (1) 简介
    // 正则表达式使用圆括号进行“组匹配”
    // const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;
    // var matchObj = RE_DATE.exec('1992-12-23');
    // console.log(matchObj[1]);
    // console.log(matchObj[2]);
    // console.log(matchObj[3]);
    // 组匹配的问题:只能使用数字序号进行引用,要是组的顺序变了,引用的时候就必须修改序号
    
    // 【提案】
    // “具名组匹配”:允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用
    // “具名组匹配”在圆括号内部,在模式的头部添加“问号+尖括号+组名”(?<year>),然后就可以在exec方法返回的结果的groups属性上引用该组名
    // const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
    // const matchObj = RE_DATE.exec('1998-12-30');
    // const year = matchObj.groups.year;
    // const month = matchObj.groups.month;
    // const day = matchObj.groups.day;
    // console.log(year, month, day);
    
    // console.log(matchObj[1]);
    
    // 具名组匹配等于为每一组匹配加上了ID,便于描述匹配的目的,如果组的顺序变了,也不用改变匹配后的处理代码
    // 如果具名组没有匹配,那么对于的groups对象属性为undefined

    // const RE_OPT_A = /^(?<as>a+)?$/;
    // const matchObj = RE_OPT_A.exec('');
    // console.log(matchObj.groups.as);  // undefined
    // console.log( 'as' in matchObj.groups);  // true


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

    // 字符串的替换,使用$<组名>引用具名组(第二个参数可以是字符串或者函数)
    // 第二个参数是字符串
    let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
    console.log('2015-01-02'.replace(re, '$<day>/$<month>/$<year>'));
    
    // 第二个参数是函数
    // '2015-01-02'.replace(re, (
    //     matched,
    //     capture1,
    //     capture2,
    //     capture3,
    //     position,
    //     S,
    //     groups
    // ) => {
    //     let {day, month, year} = args[args.length - 1];
    //     return `${day}/${month}/${year}`;
    // });



    // (3) 引用
    // 如果要在正则表达式内部引用某个“具名组匹配”,可以使用\k<组名>的写法
    // const RE_TWICE = /^(?<word>[a-z]+)!\k<word>$/;
    // console.log(RE_TWICE.test('abc!abc'));  // true
    // console.log(RE_TWICE.test('abc!ab'));  // false

    // 数字引用(\1)依然有效
    // const RE_TWICE = /^(?<word>[a-z]+)!\1$/;
    // console.log(RE_TWICE.test('abc!abc'));  // true
    // console.log(RE_TWICE.test('abc!ab'));  // false
    
    // 两种引用可以同时使用
    const RE_TWICE = /^(?<word>[a-z]+)!\k<word>!\1$/;
    console.log(RE_TWICE.test('abc!abc!abc'));  // true
    console.log(RE_TWICE.test('abc!abc!ab'));  // false
    
    
    
    
    </script>
</body>
</html>

让学习“上瘾”,成为更好的自己!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值