加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

正则表达式 捕获组,向前引用,零宽度断言,贪婪量词,惰性量词以及

发布时间:2020-12-14 04:24:45 所属栏目:百科 来源:网络整理
导读:原来写过一篇正则表达式的文章 http://hi.baidu.com/kabike/item/305cb3e591bbf4b52f140ba7 后来又读了一遍《精通正则表达式》,感觉有了新的认识. 捕获组 正则表达式中的括号相当于一个分组,比如下面这个正则表达式,就把字符串分成了"_"分割的三个分组, 然后
原来写过一篇正则表达式的文章
http://hi.baidu.com/kabike/item/305cb3e591bbf4b52f140ba7
后来又读了一遍《精通正则表达式》,感觉有了新的认识.

捕获组
正则表达式中的括号相当于一个分组,比如下面这个正则表达式,就把字符串分成了"_"分割的三个分组,
然后可以利用$1引用第一个分组,$3引用第三个分组
Java代码
  1. Patternp=Pattern.compile("([^_]+)_(d+)_([^_]+)");
  2. Stringsrc1="孙燕姿_20091103_遇见.mp3";
  3. Matcherm=p.matcher(src1);
  4. System.out.println(m.replaceAll("$1_$3"));
  5. //output孙燕姿_遇见.mp3

向前引用
假设想匹配字符串中的"hello hello"这样的字串是很容易的,但是想匹配所有的这样的重复字符串呢(比如 "aaa aaa"和"www www")?
可以利用向前引用,即寻找已经匹配的捕获组.
比如下面这个正则表达式,寻找这样的匹配模式:多个字母(形成了捕获组1),一个空格,捕获组1
Patternp=Pattern.compile("(w+)s1");
  • Stringsrc="Ialwaysmakemakesomemistakeswhenwhenwritting.";
  • Matcherm=p.matcher(src);
  • while(m.find()){
  • System.out.println(m.group());
  • }
  • //outputmakemake
  • whenwhen

  • 零宽度断言
    假设想提取字符串中的括号中的数字(不包括括号),其实可以用这样的模式
    (d+)
    但是这样会把括号也包括到匹配结果中,还要最后去掉括号.这时可以考虑零宽度断言,零宽度断言就像一种判断,匹配的模式为: 多个数字,并且这些数字之前是"(",并且这些数字之后是")"
    Patternp=Pattern.compile("(?<=()d+(?=))");
  • Stringsrc="someuselessword(497872028)someothercrap1321112232";
  • //output497872028

  • 这个可以有如下变体.提取括号以及@@之间的 数字(不包括括号和@@)
    Patternp=Pattern.compile("(?<=(|@@)d+(?=)|@@)");
  • Stringsrc="some@@497872027@@uselessword(497872028)someothercrap1321112232";
  • //output497872027
  • 贪婪量词和惰性量词
    考虑这个例子,提取##之间的部分(包括#),很容易想
    Patternp=Pattern.compile("#.+#");
  • Stringsrc="some#stupid#wordandsomecrap";
  • //#stupid#

  • 那么字符串改一下呢
    Stringsrc="some#stupid#wordandsome#crap#";
  • //#stupid#wordandsome#crap#

  • 因为默认情况下正则表达式的量词(即那个+)是贪婪的,它尝试尽可能多的匹配.
    这时可以试下惰性量词,在+后面加?,表示尽可能少的进行匹配.
    Patternp=Pattern.compile("#.+?#");
  • //#stupid#
  • //#crap#

  • 其实不用惰性量词,用 #[^#]+# 也可以
    支配量词
    支配量词比较复杂,我也不是完全清楚,这里谈一些个人见解,sans-serif; font-size:14px; line-height:25.2px">我感觉它工作起来像贪婪量词,但是它不回溯,因为支配量词丢弃原来的状态.
    比如贪婪量词模式 是w+:
    字符串是 hello,那么这个字符串是肯定不满足模式的,因为它末尾没有那个分号.
    不过贪婪量词先用 w+匹配 hello,发现不成功,进行回溯,就是用w+匹配hell,依然失败,接着匹配hel.
    直到完全失败为止.
    支配量词模式为w++:
    在w++匹配了hello之后,发现后面没有分号,匹配失败,要进行回溯.但是支配量词没有保留h he hel hell这几个中间状态,sans-serif; font-size:14px; line-height:25.2px">所以无法回溯,直接失败.
    因此支配量词在这种情况下理论上效率会高一些,因为它少了这些回溯中间状态的步骤.
    先看贪婪量词
    Patternp=Pattern.compile("w+:");
  • StringBuildersb=newStringBuilder();
  • for(inti=0;i<=40;i++){
  • sb.append("alonglongsentence");
  • Stringsrc=sb.toString();
  • longstart=System.currentTimeMillis();
  • 100;i++){
  • p.matcher(src).find();
  • System.out.println(System.currentTimeMillis()-start);
  • //1391

  • 下面用支配量词
    Patternp=Pattern.compile("w++:");
  • //875

  • 上面都是匹配失败的情况,下面试试成功的.因为成功不需要回溯,因此速度快了很多嘛.为了对比,我把字符串长度和匹配次数都变大了.
    400;i++){
  • sb.append(":");
  • 1000;i++){
  • //250
  • //235

  • 现在差别就不明显了.
    关于贪婪量词和支配量词
    我猜测字符串a12b 和模式ad+c匹配过程如下
    那个逗号表示匹配的位置
    ,a12b,ad+c
    a,12b a,d+c
    a1,2b a,d+c 记录回溯状态 a1,2b ad+,c
    a12,b a,d+c 记录回溯状态 a12,b ad+,sans-serif; font-size:14px; line-height:25.2px">b匹配d失败,回溯状态为a12,sans-serif; font-size:14px; line-height:25.2px">b匹配c失败,回溯状态为a1,sans-serif; font-size:14px; line-height:25.2px">2匹配c失败,没有状态可以回溯,匹配失败
    换成支配量词
    a12b ad++c

    看出来支配量词回溯步骤变少了.a b之间的数字越多,它比贪婪量词要回溯的就越少


    原文地址:http://kabike.iteye.com/blog/1759373

    (编辑:李大同)

    【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

      推荐文章
        热点阅读