正则式学习备忘

1,正向预搜索
     正向预搜索:"(?=xxxxx)","(?!xxxxx)"
    格式:"(?=xxxxx)",在被匹配的字符串中,它对所处的 "缝隙" 或者 "两头" 附加的条件是:所在缝隙的右侧,必须能够匹配上 xxxxx 这部分的表达式。因为它只是在此作为这个缝隙上附加的条件,所以它并不影响后边的表达式去真正匹配这个缝隙之后的字符。这就类似 "/b",本身不匹配任何字符。"/b" 只是将所在缝隙之前、之后的字符取来进行了一下判断,不会影响后边的表达式来真正的匹配。

    举例1:表达式 "Windows (?=NT|XP)" 在匹配 "Windows 98, Windows NT, Windows 2000" 时,将只匹配 "Windows NT" 中的 "Windows ",其他的 "Windows " 字样则不被匹配。

    举例2:表达式 "(/w)((?=/1/1/1)(/1))+" 在匹配字符串 "aaa ffffff 999999999" 时,将可以匹配6个"f"的前4个,可以匹配9个"9"的前7个。这个表达式可以读解成:重复4次以上的字母数字,则匹配其剩下最后2位之前的部分。当然,这个表达式可以不这样写,在此的目的是作为演示之用。
分析:
aaa ffffff 999999999,后面仅跟着2个a,不符合预搜索项(?=/1/1/1)
aaa ffffff 999999999,后面有多于3个f,符合预搜索项,接着匹配预搜索像的后面项也就是(/1),所以,匹配的结果如下aaaffffff 999999999,要注意预搜索像只是一个预搜索的判断条件,不参与真正的匹配。然后依次
aaa ffffff 999999999,ff后面还有超过3个f,就再匹配一个f
aaa ffffff 999999999,。。
aaa ffffff 999999999,后面仅有2个f,不符合预搜索像,结束匹配

格式:"(?!xxxxx)",所在缝隙的右侧,必须不能匹配 xxxxx 这部分表达式。

    举例3:表达式 "((?!/bstop/b).)+" 在匹配 "fdjka ljfdl stop fjdsla fdj" 时,将从头一直匹配到 "stop" 之前的位置,如果字符串中没有 "stop",则匹配整个字符串。

    举例4:表达式 "do(?!/w)" 在匹配字符串 "done, do, dog" 时,只能匹配第二个 "do"。在本条举例中,"do" 后边使用 "(?!/w)" 和使用 "/b" 效果是一样的。
 

-----------------------
2,反向预搜索
反向预搜索:"(?<=xxxxx)","(?<!xxxxx)"

    这两种格式的概念和正向预搜索是类似的,反向预搜索要求的条件是:所在缝隙的 "左侧",两种格式分别要求必须能够匹配和必须不能够匹配指定表达式,而不是去判断右侧。与 "正向预搜索" 一样的是:它们都是对所在缝隙的一种附加条件,本身都不匹配任何字符。

    举例5:表达式 "(?<=/d{4})/d+(?=/d{4})" 在匹配 "1234567890123456" 时,将匹配除了前4个数字和后4个数字之外的中间8个数字。
 
        String str  =   " 1234567891234 " ;
        Pattern p = Pattern.compile("(?<=//d{4})//d+(?=//d{4})");

        Matcher m 
=  p.matcher(str);
        
while (m.find()) {
            System.out.println(m.group());
        }
输出中间的56789
如果 Pattern p = Pattern.compile("(?<=//d{4})//d+?(?=//d{4})");进行非贪婪匹配,则依次输出
5
6
7
8
9
如果
Pattern p = Pattern.compile("(?=//d{4})//d+?(?=//d{4})");第一项也进行正向预搜索,则依次输出1-9

--------------------------
3,非捕获组   
(?:X)
这个是非捕获组,其实这个对结果不影响的,只是说你这个括号不是分组,只是为了吧一段规则包含起来。因为保存分组需要时间和内存,给你个例子。这个。呵呵。也算是抄的吧。别的网上看的

(?:(/w)/1)+
这 里有几个分组?答案是1个。就是(/w),然后/1就是对(/w)这个分组的引用。而外面的(?:)就不是分组了。但是我需要多个(/w)/1的时候,我 需要引用(/w),但对外面的,不需要取这个分组。就可以取消这个分组,这个是关系到效率的问题。在海量数据检索的时候。使用非捕获组可以提高一点效率。 这个我检查过,大约用非捕获组可以提高10%~20%的效率。

--------------------------
4,原子组 (?>X)
这个是原子组。我就不解释了。直接帖给你:
原子组的目的是使正则引擎失败的更快一点。因此可以有效的阻止海量回溯。原子 组的语法是<<(?>正则表达式)>>。位于(?>)之间的所有正则表达式都会被认为是一个单一的正则符号。一旦匹 配失败,引擎将会回溯到原子组前面的正则表达式部分。前面的例子用原子组可以表达成<<^(?>(.*?,){11})P> >。一旦第十二个字段匹配失败,引擎回溯到原子组前面的<<^>>。

原子组与防止回溯

在一些特殊情况下,因为回溯会使得引擎的效率极其低下。

让我们看一个例子:要匹配这样的字串,字串中的每个字段间用逗号做分隔符,第12个字段由P开头。

我 们容易想到这样的正则表达式<<^(.*?,){11}P>>。这个正则表达式在正常情况下工作的很好。但是在极端情况下,如果 第12个字段不是由P开头,则会发生灾难性的回溯。如要搜索的字串为“1,2,3,4,5,6,7,8,9,10,11,12,13”。首先,正则表达式 一直成功匹配直到第12个字符。这时,前面的正则表达式消耗的字串为“1,2,3,4,5,6,7,8,9,10,11,”,到了下一个字符,< <P>>并不匹配“12”。所以引擎进行回溯,这时正则表达式消耗的字串为“1,2,3,4,5,6,7,8,9,10,11”。继续 下一次匹配过程,下一个正则符号为点号<<.>>,可以匹配下一个逗号“,”。然而<<,>>并不匹配 字符“12”中的“1”。匹配失败,继续回溯。大家可以想象,这样的回溯组合是个非常大的数量。因此可能会造成引擎崩溃。

用于阻止这样巨大的回溯有几种方案:

一种简单的方案是尽可能的使匹配精确。用取反字符集代替点号。例如我们用如下正则表达式<<^([^,/r/n]*,){11}P>>,这样可以使失败回溯的次数下降到11次。

另一种方案是使用原子组。

原 子组的目的是使正则引擎失败的更快一点。因此可以有效的阻止海量回溯。原子组的语法是<<(?>正则表达式)>>。位于 (?>)之间的所有正则表达式都会被认为是一个单一的正则符号。一旦匹配失败,引擎将会回溯到原子组前面的正则表达式部分。前面的例子用原子组可以 表达成<<^(?>(.*?,){11})P>>。一旦第十二个字段匹配失败,引擎回溯到原子组前面的<< ^>>。


待续。。。

学习资料:http://www.regexlab.com/zh/regref.htm 
java API class Pattern
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值