王囧草

导航

 

正则基础教程一些冷门的知识

正则引擎

正则分几种引擎也从是本书获得的知识点之一。

DFA

传统型NFA

POSIX NFA

NFA范围更广,例如 JAVA, PHP, Ruby, .NET... 你是看不起我javascript所以才不列入的吗?

使用DFA的是flex, MySQL, lex, awk大部分版本… 实话说,除了mysql,都没听过。不过不用在意!

 

两个引擎的区

NFA 更注重表达式

DFA 文本主导

  通过书中里例子说,NFA 用表达式来匹配文本,而 DFA 是文本来匹配文表达式。当写好一个正则之后,NFA 是先检查表达式,同时检查文本是否匹配这个表达式。而 DFA 则是先扫描文本,然后处理表达式中的所有匹配可能,如果匹配失败,就将这条可能的线,淘汰。所以这里衍生一个概念就是回溯,NFA 有回溯,而 DFA 没有。

 

知识点

  作为一个菜鸟,正则表达式一直是书到用时方恨少的角色。平时都是能抄则抄,不能抄的时候干着急,只能用 substr, indexOf, chatAt等等的方法实现功能,既不优雅也不够装逼。上网学习也都是菜鸟教程,W3school。然后下面说一下以上两个基础教程里没说到的知识点。

 

  括号捕获与反向引用

  当你在正则表达式里使用了 (),在表达式匹配时,它能记住或者说缓存括号内匹配的结果,从而可以拿到括号内的结果,可以重复使用或者只需要括号内的结果,来剔除不需要的匹配内容。

 

// 我们经常会用 match 方法来匹配字符串,结果是一个数组,而不是最后的匹配结果,为什么呢?看下面的例子

"abc".match(/(a)(b)(c)/) // ["abc", "a", "b", "c"]

"abc".match(/abc/) // ["abc"]

  可以看到,括号会缓存括号里匹配的内容,单独列出来,那么怎么拿到括号内的内容呢,而不是通过 match 返回的结果拿,因为有时候我们需要在表达式里使用捕获的值,从而达到匹配重复的内容。这部分就叫反向引用。

 

"abc-abc-cba".replace(/(a)(b)c-\1\2/, '') // c-cba

"abc-abc-cba".replace(/(a)(b)c/g, '$1$2') // ab-ab-cba

RegExp.$1 // a

RegExp.$2 // b

  这里展示了两种使用反向引用的方法,一种是在表达式内通过 \1\2 的形式拿到两个缓存的值,一种是使用 $1$2的形式拿到。因为正则是从左开始匹配的,所以 (a) 就是第一个捕获的匹配值,所以他是\1 或是 $1,以此类推。

 

  非捕获型括号

  上面说了括号会捕获值,一般来说这样会影响性能,或者你会用到括号来做分组,但是不想捕获的情况,(?:)非捕获型括号就是这么用的,那么重写一下上面的例子。

 

"abc-abc-cba".replace(/(a)(?:b)c-\1\2/, '') // 匹配失败了,因为\2不存在

"abc-abc-cba".replace(/(a)(?:b)c-\1/, '') // bc-cba

RegExp.$1 // a

RegExp.$2 // ""

  环视

 

 

类型 正则表达式

肯定逆序环视 ?<=

否定逆序环视 ?<!

肯定顺序环视 ?=

否定顺序环视 ?!

  ?= ?! 在菜鸟和w3school 里有简单的提及,菜鸟里还提到这两个还能重写捕获,但是 ?<= ?<! 并没有提及。

 

  写几个 demo 表示一下:

 

// 找一个字母 a ,它紧跟在 b 前面

"abac".replace(/a(?=b)/g, '') // bac

 

// 找到一个字母 a ,它紧跟在一个不是 b 的字母前面

"abac".replace(/a(?!b)/g, '') // abc

 

// 接着是逆序环视

// 找到一个字母 a ,它跟在 b 后面

"abac".replace(/(?<=b)a/g, '') // abc

 

// 找到一个字母 a ,他不跟在 b 后面

"abac".replace(/(?<!b)a/g, '') // bac

 

// 一个有趣匹配

// a b 之间插入一个 ""

"abac".replace(/(?<=a)(?=b)/g, "") // abac

  可以看出,环视是要和捕获括号一起用的,并且不会占用匹配字符,他只是检查表达式是否匹配。所以这就是重写捕获了。

 

忽略优先量词

  量词匹配一般有三种 *+?。然而还可以写作, *? +? ,使匹配结果导向完全不同的结果。例子:

 

"abc-aaa-abc-abc".replace(/abc-.*-abc/, '') // ""

 

"abc-aaa-abc-abc".replace(/abc-.*?-abc/, '') // "-abc"

  *? 忽略优先会先忽略当前匹配的值,先匹配后面的 -abc,如果匹配失败,再匹配自己,而 *会优先匹配自己,等匹配结束之后,再从后面一点点吐出,回来匹配量词后面的表达式。从而造成以上不同的结果。知道这个之后,就不会再傻傻的把 * ? 分开解读了。当然,具体情况具体分析,到底使用哪个。

 

回溯

回溯应该算是正则里的性能杀手了吧。如果表达式写的不好,造成过度的灾难性回溯,会导致执行时间指数级增长。

 

喜欢这样文章的可以关注我,我会持续更新,你们的关注是我更新的动力!需要更多java学习资料的也可以私信我!

祝关注我的人都:身体健康,财源广进,福如东海,寿比南山,早生贵子,从不掉发!

 

<o2�% :�08�2<="" p="">

 i++;

 }else

 i++;

 

 }

 }

 //获取截取后的最后一个字符串

 return sourceStr.substring(sourceStr.lastIndexOf(indexStr)+indexStr.length(),sourceStr.length());

 }

 public static void main(String[] args) {

 System.out.println(indexOf("ws++rq++sl++dl","++",3));

 }

}

喜欢这样文章的可以关注我,我会持续更新,你们的关注是我更新的动力!需要更多java学习资料的也可以私信我!

 

祝关注我的人都:身体健康,财源广进,福如东海,寿比南山,早生贵子,从不掉发!

 

posted on 2020-02-28 16:04  王囧草  阅读(165)  评论(0编辑  收藏  举报