`

转载:java正则表达式非捕获组详解

    博客分类:
  • Java
阅读更多

    这几天看了下正则表达式,对非捕获组(non-capturing)进行下总结。
    

     在API中定义如下:

 

Special constructs (non-capturing)
(?:X) X, as a non-capturing group
(?idmsux-idmsux) Nothing, but turns match flags id m su x on - off
(?idmsux-idmsux:X) X, as a non-capturing group with the given flags i dm s ux on - off
(?=X) X, via zero-width positive lookahead
(?!X) X, via zero-width negative lookahead
(?<=X) X, via zero-width positive lookbehind
(?<!X) X, via zero-width negative lookbehind
(?>X) X, as an independent, non-capturing group


 这里主要介绍:(?:X) (?=X) (?<=X) (?!X) (?<!X)
 
一、先从(?:)非捕获组说起。
下面由一个例子引出非捕获组。
有两个金额:8899¥ 和 6688$ 。显然,前一个是8899元的人民币,后一个是6688元的美元。我现在需要一个正则,要求提炼出它们的货币金额和货币种类。正则可以这写:(\\d)+([¥$])$  (在java中测试,所以多了转义字符'\')
测试程序如下:
[java] view plaincopy

01. Pattern p = Pattern.compile("(\\d+)([¥$])$"); 
02.      String str = "8899¥"; 
03.      Matcher m = p.matcher(str); 
04.      if(m.matches()){ 
05.       System.out.println("货币金额: " + m.group(1)); 
06.       System.out.println("货币种类: " + m.group(2)); 
07.      }  
 

输出结果为:
 货币金额: 8899
 货币种类: ¥
 
OK,满足了要求。这里的正则分成了两个组,一个是(\\d+),一个是([¥$]),前一个组匹配货币金额,后一个组匹配货币种类。
 
现在,我需要这个正则可以匹配浮点数。如8899.56¥。我们都知道,现在少于一元钱基本上买不到东西了,所以我希望忽略小数部分,正则还是提炼出 8899 和 ¥。那么正则如下:
 [code="java"] (\\d+)(\\.?)(\\d+)([¥$])$ [/code]
这里用括号分了四组,所以要输出货币金额的整数部分和货币种类,要分别输了group(1),group(4)了。如果输出部分和正则是分开的,我希望只修改正则而不去修改输出部分的代码,也就是还是用group(1),group(2)作为输出。由此可以引出非捕获组(?:)。
 把前面的正则修改为:
 [code="java"] (\\d+)(?:\\.?)(?:\\d+)([¥$])$ [/code]
 这样,还是用group(1),group(2)做为输出,同样输出了 8899 和 ¥
 这个正则的中间两个组用到的就是非捕获组(?:),它可以理解为只分组而不捕获。
 
二、(?=)和(?<=)
有的资料把它们叫做肯定式向前查找和肯定式向后查找;有的资料也叫做肯定顺序环视和肯定逆序环视。
1、姑且不理它们的名称,看下面的例子:


[java] view plaincopy

01. Pattern p = Pattern.compile("[0-9a-z]{2}(?=aa)"); 
02.    String str = "12332aa438aaf"; 
03.   
04.    Matcher m = p.matcher(str); 
05.    while(m.find()){ 
06.          System.out.println(m.group()); 
07.    } 
 

 

这段程序输出32 38
这个正则的意思是:匹配这么一个字符串,它要满足:是两位字符(数字,或字母),且后面紧跟着两个a。
分析一下:
32aa  这个子串 满足这个条件,所以可以匹配到,又因为 (?=) 的部分是不捕获的,所以输出的只是 32,不包括aa。同理 38aa 也匹配这个正则,而输出仅是 38。
 
再深入看一下:
当str第一次匹配成功输出 32 后,程序要继续向后查找是否还有匹配的其它子串。那么这时应该从 32aa 的后一位开始向后查找,还是从 32 的后一位呢?也就是从索引 5 开始还是从 7 开始呢?有人可能想到是从 32aa 的下一位开始往后找,因为 32aa 匹配了正则,所以下一位当然是它的后面也就是从 4 开始。但实际上是从 32 的后一位也就是第一个 a 开始往后找。原因还是 (?=) 是非捕获的。
查阅API文档是这么注释的:
 
(?=X) X, via zero-width positive lookahead
 
可见zero-width(零宽度)说的就是这个意思。
 
现在,把字符串写的更有意思些:str = "aaaaaaaa";
 看一下它的输出: aa aa aa
 分析一下:
 这个字符串一共有8个a。
 第一次匹配比较容易找到,那就是前四个:aaaa ,当然第三和第四个 a 是不捕获的,所以输出是第一和第二个a;
 接着继续查找,这时是从第三个a开始,三到六,这4个a区配到了,所以输出第三和第四个a;
 接着继续查找,这时是从第五个a开始,五到八,这4个a区配到了,所以输出第五和第六个a;
 接着往后查找,这时是从第七个a开始,显然,第七和第八个a,不满足正则的匹配条件,查找结束。
 我们再延伸一下,刚说的情况的是(?=)放在捕获的字符串后面,它如果放在前面又是什么结果呢?
例子换成:

 
[java] view plaincopy

01. Pattern p = Pattern.compile("(?=hopeful)hope"); 
02.     String str = "hopeful"; 
03.     Matcher m = p.matcher(str); 
04.     while(m.find()){ 
05.       System.out.println(m.group()); 
06.     }  
 

它的输出是hope。
正则的意思是:是否能匹配hopeful,如果能,则捕获hopeful中的hope。当然继续向后查找匹配的子串,是从f开始。
比较一下可以看出,(?=hopeful)hope 和 hope(?=ful),两个正则的效果其实是一样的。
 
2、下面说一下 (?<=)
把正则改一下,
Pattern p = Pattern.compile("(?<=aa)[0-9a-z]{2}");
字符串还是str = "12332aa438aaf";
它的输出:43。

 
这个正则的意思是:匹配这么一个字符串,它要满足:是两位字符(数字或字母),且前面紧跟的是两个字母 a 。
 
同样,深入一下,把str换成str = "aaaaaaaa";看一下输出是什么,同样也是:aa aa aa
 分析一下:
 第一次匹配不用说,是前四个a,输出的是第三和第四个a;
 继续向后查找,从第五个a开始,程序发现,第五个和第六个a满足,因为是两位字符,且满足前面紧跟着两个a(第三和第四个a)。所以匹配成功,输出第五个和第六个a;
 继续向后查找,从第七个a开始,程序发现,第七个和第八个a满足,因为是两位字符,且满足前面紧跟着两个a(第五和第六个a)。所以匹配成功,输出第七和第八个a。查找结束。
 
三、(?!)和(?<!)
 从外观上看,和前面一组很相似,区别就是把 ‘=’ 换成了 ‘!’
 那么意义刚好也是相反的。
 [0-9a-z]{2}(?!aa)    意思是:匹配两个字符,且后面紧跟着的不是aa
 (?<!aa)[0-9a-z]{2}  意思是:匹配两个字符,且前面紧跟着的不是aa
 用法和前面讲的差不多,这里不再详述。

分享到:
评论

相关推荐

    java正则表达式详解

    ### Java正则表达式详解 #### 一、正则表达式基础知识 正则表达式是一种强大的文本处理工具,被广泛应用于各种编程语言中,用于文本的查找与替换、验证等场景。Java作为一种主流的编程语言,同样支持正则表达式的...

    JAVA正则表达式大全

    3. **Java正则表达式详解** Java中的正则表达式主要通过`java.util.regex`包来实现,核心类有`Pattern`和`Matcher`。`Pattern`是编译正则表达式的对象,编译后可以多次使用。`Matcher`对象是实际执行匹配操作的对象...

    Java正则表达式详解(非常适合入门

    ### Java正则表达式详解 #### 一、正则表达式的重要性及应用 正则表达式,作为一种强大的文本处理工具,对于程序员而言是不可或缺的基本技能之一。它在文本的匹配、搜索和替换等方面发挥着不可替代的作用。尤其在...

    java正则表达式详解(PDF)

    通过这份"java正则表达式详解(PDF)"文档,读者将能深入了解Java正则表达式的各个方面,掌握如何在实际项目中有效地运用正则表达式进行字符串处理。无论你是Java初学者还是经验丰富的开发者,这份资料都将是一份...

    Java正则表达式详解.pdf

    ### Java正则表达式详解:掌握文本匹配的艺术 正则表达式,又称正则规则或正则模式,是一种用于描述字符串结构的语法,被广泛应用于各种编程语言中,包括Java,用于文本处理、数据验证、搜索与替换等场景。本文将...

    详解Java判断是否是整数,小数或实数的正则表达式

    在Java中使用正则表达式来判断字符串是否符合整数、小数或实数的格式是一种常见且有效的做法。在编程中,我们经常需要对输入的字符串进行格式验证,以确保它们符合预期的数值格式,尤其是在处理财务数据、用户输入...

    java正则表达式及例子 pdf

    Java正则表达式是Java编程语言中用于处理字符串的强大工具,...通过阅读《Java 正则表达式的总结和一些小例子.pdf》和《Java正则表达式详解.pdf》,你将能够深入学习和实践更多正则表达式的用法,进一步提升编程技能。

    正则表达式入门 正则表达式详解

    正则表达式不仅适用于JAVA,还广泛应用于Python、JavaScript、C#等语言。 在JAVA中,正则表达式的使用基于`java.util.regex`包,提供了`Pattern`和`Matcher`两个主要类。`Pattern`类用于编译正则表达式,而`Matcher...

    Java 正则表达式详解

    总结来说,Java正则表达式提供了一套强大的工具来处理文本,通过理解基本的正则表达式语法和Java提供的相关API,开发者可以有效地搜索、替换和解析文本,满足各种复杂的需求。无论是在开发、数据分析还是日志分析等...

    java 正则表达式详解

    ### Java正则表达式详解 #### 一、引言 正则表达式是计算机科学领域中一种非常强大的工具,用于模式匹配和文本处理。在多种编程语言中都有应用,包括Perl、PHP、Python、JavaScript等。Java作为一种广泛使用的编程...

    java正则表达式pdf格式

    本PDF文档《Java正则表达式详解》深入探讨了这一主题,旨在帮助开发者更高效地利用正则表达式解决实际问题。 一、正则表达式基础 1. 正则表达式的组成:正则表达式由各种字符和特殊符号构成,如`.`(匹配任意单个...

    正则表达式详解(20分钟看懂正则)

    ### 正则表达式详解 #### 一、正则表达式概述 正则表达式是一种强大的文本模式匹配工具,广泛应用于编程语言如Java中,用于处理字符串数据,实现字符串的搜索、替换、提取等操作。它能够精确描述复杂的文本规则,...

Global site tag (gtag.js) - Google Analytics