【regex】忽略优先量词

忽略优先量词

正则里的忽略优先量词有 *?+???,也就是匹配优先量词加上一个?,忽略优先也叫做我们平时说的惰性匹配

忽略优先量词也是DFANFA的分水岭,这个东西是NFA里特有的,DFA里没有的。

忽略优先量词与匹配优先量词不同的地方在于,匹配优先量词会首先尝试匹配,而忽略优先量词会先尝试忽略,在保存状态的时候也是不一样的,匹配优先量词因为会先尝试匹配,所以它的备用状态保存在该量词的后面,而忽略优先量词, 因为它会先尝试忽略, 所以状态保存在该量词的前面。

结合匹配优先量词,来看一个例子

假如我现在有这样一个字符串

hello my name is "zhangsan", and my father name is "zhangsi"

如果现在我们要匹配前面引号里面的 zhangsan我们应该怎么做,我们好像可以直接zhangsan,这样,但是这只是个特例,我们的初衷是为了匹配引号中的东西。

如果我们用".*"来匹配呢?那匹配到的结果肯定是

"zhangsan", and my father name is "zhangsi"

这是为啥?

因为*是匹配优先的量词啊,在进行匹配的时候,*肯定是会先尝试匹配,它会将整个文本都匹配完, 当控制权来到"手上时,它交出最后一个字符",此时匹配成功,所以匹配的结果是这个。

但是这不是我们想要的结果啊!那我们应该如何来匹配?答案是用忽略优先量词".*?"

在开始匹配的时候,*?会因为是忽略优先而放弃匹配,然后控制权交给",发现匹配失败,回溯,接着匹配,以此往复,当匹配到"时,匹配成功,匹配结果为 :

"zhangsan"

太好了!这是我们想要的结果!

我们发现,匹配优先量词会先贪婪的把能匹配的都匹配了,然后最后再以大局为重被迫交出几个字符,这样看好像是从后往前来匹配的,而忽略优先量词会懒惰的不想匹配,然后再以大局为重被迫匹配几个字符,在这样看好像是顺序匹配的。

假如有一篇长篇大论,然而你只想匹配开头的子串的话,你应该首先选择忽略优先量词,如果你只是想匹配后面的子串,你应该首先选择匹配优先量词

不妨在看一个比较极端的例子

function targetStringFactory() {
  let attachStr = "a";
  let originStr = "abcd1234";
  let attachArr = [];

  for (let i = 0; i < 1000000; i++) {
    attachArr.push(attachStr);
  }

  return [originStr, ...attachArr].join("");
}

let str = targetStringFactory();

console.time("greedy");
str.match(/.*[0-9]{4}/);
console.timeEnd("greedy");

console.time("lazy");
str.match(/.*?[0-9]{4}/);
console.timeEnd("lazy");

我只是想匹配开头的abcd1234,后面跟着 1000000 个 a,这时候,我们把匹配优先量词忽略优先量词最一个对比

greedy: 5.238ms
lazy: 0.113ms

发现忽略优先量词确实比匹配优先量词要快的多…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值