正则的扩展

本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2020-06-15

后行断言

“先行断言” 指的是,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"] 匹配不在百分号之前的数字

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

var result = /(?<=\$)\d+/.exec('Benjamin Franklin is on the $100 bill')  
// ["100"] 只匹配美元符号之后的数字
var result2 = /(?<!\$)\d+/.exec('it’s is worth about €90') 
// ["90"] 只匹配不在美元符号后面的数字

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

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

没有“后行断言”时,第一个括号是贪婪模式,第二个括号只能捕获一个字符,所以结果是1053

而“后行断言”时,由于执行顺序是从右到左,第二个括号是贪婪模式,第一个括号只能捕获一个字符,所以结果是1053

具名组匹配

正则表达式使用圆括号进行组匹配。

const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;

const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj[1]; // 1999
const month = matchObj[2]; // 12
const day = matchObj[3]; // 31

ES2018 引入了具名组匹配(Named Capture Groups),允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用。具名组如果没有找到匹配,那么其属性值就是undefined

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

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

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

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