在 ECMAScript 2018( ES2018 ) 新功能 我们介绍了 TC39 会议已经票选出了 ES2018 的新功能
本着每一小节一个新功能的原则,本小节我们介绍另一个新功能,正则表达式中的 向后查找
简介
周边查找是一个零宽度断言,用于匹配字符串而不消耗任何东西,ECMAScript 已经实现了 向前查找 断言,用于向前查找匹配情况,但它也缺少缺少一种向后查找的方式,而这种方式是 向后查找 的断言所提供的
使用 向后查找 断言,可以确定一个模式是否在另一个模式之前被匹配,例如用于匹配美元金额而不匹配美元符号 ( $
)
高阶 API
向后查找有两种版本的断言:积极断言和否定断言
-
积极向后断言的正则表达式表示为
(?<=...)
,并且它们确保包含在其中的模式在断言之后的模式之前例如,如果想要匹配一美元金额而不捕获美元符号,可以使用
/(?<=\$)\d+(\.\d*)?/
,这将匹配$10.53
并且返回10.53
。但是,这个正则表达式并不匹配€10.53
-
否定向后断言表达式表示为
(?<!...)
,并且它们确保其中的模式不在断言后的模式之前例如,
/(?<!\$)\d+(?:\.\d*)/
并不能匹配$10.53
,但可以匹配€10.53
所有正则表达式模式,甚至是无限制的模式都被允许作为向后查找断言的一部分。因此,例如,可以写一个正则表达式 /(?<=\$\d+\.)\d+/
来匹配一个美元金额并仅捕获整数金额部分
一般情况下,模式通常从最左边的子模式开始匹配,如果左子模式成功,则移动到右边的子模式。
但如果模式包含在向后查找的断言中时,匹配的顺序将会被颠倒,也就是说,模式将从最右边的子模式开始匹配,然后向左前进
例如,对于给定的正则表达式 /(?<=\$\d+\.)\d+/
,匹配时首先会找到一个数字 \d+
,然后确保这个数字的前面有一个点好 ( .
),然后点号之前在包含一些数字 \d+
,最后数字之前还必须有一个美元符号 $
,
对于匹配的结果来说,回溯的方向也会发生翻转
详情
在一个向后查找中,语义是匹配向后进行,反向引用中的正则表达式片段被反转,并且字符串从结尾向开头遍历,这对匹配模式是有一些影响的。
贪婪模式从右往左进行
首先,如果捕获组中包含了贪婪量词的子模式,那么向后查找中的捕获组的值和正常模式中的有很大的不同
-
在向后查找中,右侧的组将捕获大多数字符而不是左侧的字符,例如,对于给定的正则表达式
/(?<=(\d+)(\d+))$/
和字符串1053
, 第二个捕获组将捕获053
,第一个捕获组将捕获1
-
而在普通的模式中,对于正则表达式
/^(\d+)(\d+)/
, 第一个捕获组的值将为105
,而第二个捕获组的值将为3
捕获组编号
向后查找模式中,捕获组从左往右开始编号,在示例中, /(?<=(\d+)(\d+))$/
匹配字符串 1053
,那么 match[1]
的值为 1
,而 match[2]
的值为 053
引用捕获组
反向引用中,只能引用已经过评估的捕获组,也就是说,该组必须位于反向引用的右侧
例如,/(?<=(.)\1)/
并不是一个非常有用的正则表达式,因为 \1
不能被解析,所以只能匹配空字符串
相反,要在内容之前查找相同字母的两个副本,可以使用 /(?<=\1(.))/
否定断言
类似于 ECMAScript 正则表达式中已经存在的否定向前查找断言 /(?!.)/
,此提案还包括了否定向后查找断言 /(?<!.)/