• ES6 入门教程 6 正则的扩展 6.7 RegExp.prototype.flags 属性 & 6.8 s 修饰符:dotAll 模式 & 6.9 后行断言


    ES6 入门教程

    ECMAScript 6 入门

    作者:阮一峰

    本文仅用于学习记录,不存在任何商业用途,如侵删

    6 正则的扩展

    6.7 RegExp.prototype.flags 属性

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

    // ES5 的 source 属性
    // 返回正则表达式的正文
    /abc/ig.source
    // "abc"
    
    // ES6 的 flags 属性
    // 返回正则表达式的修饰符
    /abc/ig.flags
    // 'gi'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    6.8 s 修饰符:dotAll 模式

    正则表达式中,点(.)是一个特殊字符,代表任意的单个字符,但是有两个例外。一个是四个字节的 UTF-16 字符,这个可以用u修饰符解决;另一个是行终止符(line terminator character)。

    所谓行终止符,就是该字符表示一行的终结。以下四个字符属于“行终止符”。

    • U+000A 换行符(\n
    • U+000D 回车符(\r
    • U+2028 行分隔符(line separator)
    • U+2029 段分隔符(paragraph separator)
    /foo.bar/.test('foo\nbar')
    // false
    
    • 1
    • 2

    上面代码中,因为.不匹配\n,所以正则表达式返回false

    但是,很多时候希望匹配的是任意单个字符,这时有一种变通的写法。

    /foo[^]bar/.test('foo\nbar')
    // true
    
    • 1
    • 2

    这种解决方案毕竟不太符合直觉,ES2018 引入s修饰符,使得.可以匹配任意单个字符。

    /foo.bar/s.test('foo\nbar') // true
    
    • 1

    这被称为dotAll模式,即点(dot)代表一切字符。

    所以,正则表达式还引入了一个dotAll属性,返回一个布尔值,表示该正则表达式是否处在dotAll模式。

    const re = /foo.bar/s;
    // 另一种写法
    // const re = new RegExp('foo.bar', 's');
    
    re.test('foo\nbar') // true
    re.dotAll // true
    re.flags // 's'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    /s修饰符和多行修饰符/m不冲突,两者一起使用的情况下,.匹配所有字符,而^$匹配每一行的行首和行尾。

    6.9 后行断言

    JavaScript 语言的正则表达式,只支持先行断言(lookahead)和先行否定断言(negative lookahead),不支持后行断言(lookbehind)和后行否定断言(negative lookbehind)。

    ES2018 引入后行断言,V8 引擎 4.9 版(Chrome 62)已经支持。

    “先行断言”指的是,x只有在y前面才匹配,必须写成/x(?=y)/。比如,只匹配百分号之前的数字,要写成/\d+(?=%)/。“先行否定断言”指的是,x只有不在y前面才匹配,必须写成/x(?!y)/。比如,只匹配不在百分号之前的数字,要写成/\d+(?!%)/

    /\d+(?=%)/.exec('100% of US presidents have been male')  // ["100"]
    /\d+(?!%)/.exec('that’s all 44 of them')                 // ["44"]
    
    • 1
    • 2

    上面两个字符串,如果互换正则表达式,就不会得到相同结果。另外,还可以看到,“先行断言”括号之中的部分((?=%)),是不计入返回结果的。

    “后行断言”正好与“先行断言”相反,x只有在y后面才匹配,必须写成/(?<=y)x/。比如,只匹配美元符号之后的数字,要写成/(?<=\$)\d+/。“后行否定断言”则与“先行否定断言”相反,x只有不在y后面才匹配,必须写成/(?。比如,只匹配不在美元符号后面的数字,要写成/(?

    /(?<=\$)\d+/.exec('Benjamin Franklin is on the $100 bill')  // ["100"]
    /(?<!\$)\d+/.exec('it’s is worth about €90')                // ["90"]
    
    • 1
    • 2

    上面的例子中,“后行断言”的括号之中的部分((?<=\$)),也是不计入返回结果。

    下面的例子是使用后行断言进行字符串替换。

    const RE_DOLLAR_PREFIX = /(?<=\$)foo/g;
    '$foo %foo foo'.replace(RE_DOLLAR_PREFIX, 'bar');
    // '$bar %foo foo'
    
    • 1
    • 2
    • 3

    上面代码中,只有在美元符号后面的foo才会被替换。

    “后行断言”的实现,需要先匹配/(?<=y)x/x,然后再回到左边,匹配y的部分。这种“先右后左”的执行顺序,与所有其他正则操作相反,导致了一些不符合预期的行为。

    首先,后行断言的组匹配,与正常情况下结果是不一样的。

    /(?<=(\d+)(\d+))$/.exec('1053') // ["", "1", "053"]
    /^(\d+)(\d+)$/.exec('1053') // ["1053", "105", "3"]
    
    • 1
    • 2

    上面代码中,需要捕捉两个组匹配。没有“后行断言”时,第一个括号是贪婪模式,第二个括号只能捕获一个字符,所以结果是1053。而“后行断言”时,由于执行顺序是从右到左,第二个括号是贪婪模式,第一个括号只能捕获一个字符,所以结果是1053

    其次,“后行断言”的反斜杠引用,也与通常的顺序相反,必须放在对应的那个括号之前。

    /(?<=(o)d\1)r/.exec('hodor')  // null
    /(?<=\1d(o))r/.exec('hodor')  // ["r", "o"]
    
    • 1
    • 2

    上面代码中,如果后行断言的反斜杠引用(\1)放在括号的后面,就不会得到匹配结果,必须放在前面才可以。因为后行断言是先从左到右扫描,发现匹配以后再回过头,从右到左完成反斜杠引用。

  • 相关阅读:
    vue3基础流程
    “基础 - 中级 - 高级”Java 后端 25 个技术栈面试题集结
    lme4:用于混合效应模型分析的R包
    通过腾讯云TDSQL TCP&TCE(MySQL版)认证考试秘籍宝典
    java计算机毕业设计宠物寄存管理系统源码+mysql数据库+系统+lw文档+部署
    【IPC 通信】信号处理接口 Signal API(5)
    自动驾驶论文总结
    NoSQL之Redis配置与优化
    【java学习—十四】java动态代理(6)
    移动硬盘误删除要如何恢复呢?
  • 原文地址:https://blog.csdn.net/weixin_44226181/article/details/127858972