学会Java正则表达式,不可不看

1.正则表达式作用:
正则表达式一般是一个不确定的字符串,由字符和数字组成,使用正则表达式主要是为了匹配目标字符串中的子字符串
2.字符串的组成:
要熟悉使用正则表达式,必须清楚字符串的组成和正则表达式的匹配原理,字符串由字符和位置组成,比如字符串abc组成如图:在这里插入图片描述
3.Java正则表达式的机制:
正则表达式机制分为两种:
1.DFA(Deterministic Finite Automaton确定性有穷自动机):使用目标字符串(字符串确定)匹配正则表达式
2.NFA(Nondeterministic Finite Automaton非确定性有穷自动机):使用正则表达式(字符串不确定)匹配目标字符串
比如目标字符串s1=“cabdfab”,正则表达式字符串为s2=“ab”。在不使用全局匹配的情况下,DNF的机制是使用s1字符去匹配s2的字符,先用s1的c去匹配s2的a,不匹配,再用s1的a匹配s2的a,匹配成功,再用s1的b匹配s2的b,匹配成功,返回匹配结果;而NFA的机制是使用s2字符去匹配s1字符,先用s2的a去匹配s1的c,不匹配,再用s2的a去匹配s1的a,匹配成功,再用s2的b去匹配s1的b,匹配成功,返回匹配结果。
两种机制的比较:
1.DFA从匹配文本入手,从左到右,每个字符不会匹配两次,它的时间复杂度是多项式的,所以通常情况下,它的速度更快,但支持的特性很少,不支持捕获组、各种引用等等;
2.NFA则是从正则表达式入手,不断读入字符,尝试是否匹配当前正则,不匹配则吐出字符重新尝试,通常它的速度比较慢,最优时间复杂度为多项式的,最差情况为指数级的,但NFA支持更多的特性,因此Java采用了NFA正则表达式机制

4.巧解贪婪模式、勉强模式、占有模式:
4.1其实只有一种数量表示符:
要理解贪婪模式、勉强模式、占有模式这三种模式,得先理解贪婪模式,理解贪婪模式,则要先理解6种数量表示符:?、*、+、{n}、{n,}、{n,m},结合X表达式就形成了六种贪婪模式:X?、X*、X+、X{n}、X{n,}、X{n,m},但其实就只有一种贪婪模式X{n,m},其中X{n,}等价于m取无穷大,X{n}等价于X{n,n}X+等价于X{1,}X*等价于X{0,}X?等价于X{0,1},所以只要理解了贪婪模式的X{n,m},就理解了贪婪模式
4.2怎么理解违反常识的n=0:
继续上文,X{n,m}表示最少匹配X表达式n次,最多匹配X表达式m次,当n为0时是最让人犯糊涂的,因为匹配相当于比较,n为0,代表比较0次,我们的生活中很少有这样的说法,比如NBA湖人队和NBA火箭队重来没有打过比赛,你会给你朋友说湖人队和火箭队打了0次比赛吗?可能会(你朋友估计会用看智障的眼神看你),但很少。通过这样的例子,0的意思很明显了,0表示没有,用英语说就是nothing happen,没有发生的事。现在假设目标字符串s1=“abceda”,正则表达式s2=“a{0}”,就表示字符a就不和目标字符串s1=“abceda"的字符去逐个比较了,那都不比较了呗,a{0}自然无法匹配目标字符串s1的子字符串,有意义吗?从字面上说完全没有意义,但是把这个匹配放到http://c.runoob.com/front-end/854下测试,又见到这样的情况:
在这里插入图片描述
是不是很神奇,显示有7处匹配但是又没有具体的匹配字符,那么神奇在哪些地方呢,下面说下:
神奇1:按照0在生活中的说法,0表示没有发生,a{0}不会去匹配字符串s1=“abceda”,自然不会出现"找到匹配"这样的字样
神奇2:目标字符串s1=“abceda"只有6个字符,却出现了7处匹配这样的结果;
神奇3:显示有7处匹配但是又没有显示具体匹配的字符;
综上所述,就表示当n=0时,正则表达式的匹配规则和我们想象中的匹配常识有着很多不同的地方,现在针对结果做下分析:
1.共有7处匹配:也就说a{0}匹配了s1=“abceda"的7个地方
2.没有出现匹配字符:也就说a{0}匹配的7个地方,是不能用字符表示的,不能用字符表示,就说明匹配的不是字符
那这7个地方是哪7个地方呢,看下前面我们说的字符串组成,字符串是由字符和位置组成的,abceda共有6个字符和7个位置组成的,不难想到a{0}匹配的就是这7个位置,那验证一下吧,在http://c.runoob.com/front-end/854中输入替换文本,出现如下结果:
在这里插入图片描述
当然也可以通过Java代码验证,结果如下:
在这里插入图片描述
从上面可知当n=0,X{0}不会去和目标字符串的字符匹配,而是和目标字符串的位置去匹配,因此a{0},b{0},c{0},abc{0}作为正则表达式去匹配目标字符串的时候效果是一样的(读者可以把上面的a{0}换做b{0}测试一下)。综上所述,这种机制堪称玄学,a{0},b{0},c{0},abc{0}都可看做X{0},0代表无,字符串的位置没有通过显然可见的方式显示,因此也是无,所以X{0}去匹配目标字符串的位置相当于用无去匹配无。
4.3.先说贪婪模式下的贪婪问题和回溯问题:
4.3.1贪婪问题:
举个例子读者就知道了,假设目标字符串为s1="baaabcaabd",正则表达式为s2="a+d",前面我们说过a+相当于a{1,},因此s2相当于s2="a{1,}d",在全局搜索的情况下将匹配s1=“baaabcaabd"的子串"aaab"和"aab”,通过网址http://c.runoob.com/front-end/854验证如下:
在这里插入图片描述
由于Java采用的是NFA机制,所以这两个结果得出的过程如下:
匹配aaab的过程:
s2="a{1,}d"去匹配s1="baaabcaabd",s2会先用a先去匹配s1第一个字符b,不匹配,再去匹配s1的第二个字符a,匹配成功,满足了n=1最少匹配一次的问题,接着s1的a由于使用了贪婪模式,因此a还不满足,还要继续去匹配s2的第三个字符a,匹配成功,接着s1中的a还不满足,继续去匹配s2的第四个字符a,匹配成功,接着s1中的a还不满足,要去匹配s2的第五个字符b,匹配失败,然后用s1中的b去匹配s2的第五个字符b,匹配成功,因此s2就匹配了s1中的字符子串aaab。
匹配aab的过程:
匹配aab的过程相当于用s2="a{1,}d"去匹配s1="caabd",根据前面的思路,很容易就知道了,在此不述。
4.3.2回溯问题:
再次使用个例子说下,假如s1仍为s1="baabd"s2="\w+a",那么s2将会匹配s1的子串"baa”(读者可通过上面的正则表达式网站验证),为什么会这样呢?因为s2其实相当于s2="\w{1,}a",\w表示单词字符,因此\w可匹配所有字符,其匹配过程如下图:
在这里插入图片描述
4.4再说n=0:
前面说过,其实只有一种数量标识符X{n,m},X{0}相当于X{0,0},因此包含n=0的情况还有X{0,}X{0,1}(假设m=1),那么这三种情况X{0},X{0,}X{0,1}有什么区别呢?假设目标字符串为s1=“abaad”,通过下图匹配结果分析:
在这里插入图片描述
a{0}的作用前面我们说过了用于匹配字符串的位置(其实是匹配了空字符串),因为使用了全局搜索,因此可以匹配到6处位置,这里就不多说了,至于a{0,1}匹配目标字符串"abaad"的过程,则是先用a{0}匹配其第一个位置,匹配成功,然后因为a{0,1}是贪婪模式,所以会再次使用a去匹配"abaad"的第一个字符a,此时达到最大匹配次数1,不能再用a去匹配剩下的字符串,第一次匹配成功,依次下去匹配,匹配过程如下图:
在这里插入图片描述
a{0,}匹配目标字符串"abaad"的匹配过程如下:
在这里插入图片描述
4.5理解勉强模式:
勉强模式的语法即在贪婪模式的语法后添加?,因此勉强模式6种语法为:X??、X*?、X+?、X{n}?、X{n,}?、X{n,m}?,前面说过其实只有一种数量标识符X{n,m},只要理解了X{n,m}就理解了数量标识符,贪婪模式在使用X表达式比较目标字符串n次成功后,仍会使用X表达式去比较目标字符串,直到总匹配成功次数等于m次或遇到不能匹配的字符时返回匹配成功的结果。而勉强模式则是匹配成功n次时,先暂停以下,用其正则表达式后面第一个字符匹配目标字符串。假设目标字符串为s1=“dfada”,正则表达式为s2=”\w*?a”,用下面的图说下勉强模式的匹配过程:
在这里插入图片描述
4.6理解占有模式:
占有模式的语法即在贪婪模式的语法后加符号+,因此占有模式有6种语法为:X?+、X*+、X++、X{n}+、X{n,}+、X{n,m}+,占有模式是在贪婪模式的基础上少了回溯功能,假设目标字符串为s1=“dfada”,正则表达式为s2="\w*?a",用下面的图说下勉强模式的匹配过程:
在这里插入图片描述
5.举例说明不要拘泥于一种Java正则表达式的写法:
只要理解NFA机制、数量表示符{n,m},贪婪模式、勉强模式、占有模式,基本就弄懂了正则表达式。看多了正则表达式,写正则表达式基本是收放自如的,建议读者在满足同一要求下多想想其他正则表达式的写法,这样可增强对正则表达式的理解,在http://c.runoob.com/front-end/854下列举了校验数字表达式、校验字符表达式和特殊需求的表达式三种正则表达式的写法,下面举几个简单的例子说下满足相同要求下的正则表达式的写法:
1.数字:^[0-9]*$,等价于^\d*$,^\d{0,}$,^[0-9]*[0-9]*$
2.带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})$,等价于:^(\-|\d)\d*\.\d{1,2}$
3.长度为3-20的所有字符:^.{3,20}$,等价于^..{1,18}.$
通过这几个简单的举例,只想告诉读者学习Java正则表达式没有其他方法,唯手熟耳,多看多写自然就知道怎么写正则表达式了。

6.Java正则表达式语法应注意的一些方法:
时间有限,改天再更。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值