正则表达式(?=pattern) (?!pattern) (?:pattern)的理解

正则表达式(?=pattern)(?!pattern)(?:pattern)的理解

学习JAVA正则表达式时,(?=pattern)(?!pattern)(?:pattern)这类东西看着就挺难理解,而且官方释义更是越看越不懂。查阅资料后,总结如下。

环视

(?=pattern)与(?!pattern)属于一类,在正则表达式中叫环视。 “环视”这个词从字面理解就是确定“周围环境”。环视一共有四种:(?=pattern)、(?!pattern)、(?<=pattern)、(?

目标字符串:ABCDEFG ACDIU

现在我们用简单的字符串匹配的正则表达式:

正则表达式:CD

显然会得到两个结果,一个是“ABCDEFG”中的CD,一个是“ACDIU”中的CD;现在我不想匹配到后面的那个CD,因为我只想匹配紧接着"EFG"的那个CD,环视就可以派上用场(当然,这种简单的例子,其他方式也完全可以解决),我们可以这么做:

正则表达式1:CD(?=EFG)

此时,我们只会得到一个结果,就是“ABCDEFG”中的CD!这是为什么呢?这就是(?=pattern)起的作用。我们模拟下正则表达式的处理过程(当然,我暂时没有学习正则表达式引擎的原理,不确定是否就是完全正确的过程,但是有助于理解):引擎从左向右扫描,扫描到“ABCDEFG”中的CD时,第一次扫描到“CD”字符,然后执行环视,(?=)表示顺序环视,也就是向字符串右边看,观察后面的字符是否是“EFG”,如果是,则匹配成功;如果不是,则丢弃这个匹配。因此出现了上述结果。
下面看逆序环视:

正则表达式2:(?<=A)CD

此时,向左看,看是否是“A”字符,因此,正则表达式2只能匹配到“ACDIU”中的CD。

环视不消耗字符

还是用示例来理解:

正则表达式3:CD(?=EF)G

正则表达式3运行后能匹配到东西吗?答案是不能!理解环视不消耗字符很重要:引擎在扫描到“CD”后,执行环视,观察右边是否有“EF”字符,结果是观察到了,那么继续匹配后面的,但此时引擎仍然从“D”这个字符的位置往后扫描。因为,扫描到“CD”后,引擎在环视的过程中并没有消耗后面的“EF”字符,引擎仍从上次扫描的位置接着扫描,显然“D”后面的字符不是“G”,因此匹配失败。
如果改成下面的表达式,就能匹配到了:

正则表达式3:CD(?=EF)E

本质:环视不匹配任何字符,只匹配文本中的特定位置

前面说了那么多,其实是为了好理解。但说法可能并不规范,真正的环视的理解是这样的:环视不匹配任何字符,只匹配文本中的特定位置。环视是为了定位特定的位置,如果目标字符串中这个位置(位置可能是多个)的左右字符能(否定环视则是不能)匹配上正则表达式中环视表达式左右的字符串,那么匹配成功,这点非常重要。
不太好解释,直接上示例吧:

正则表达式4:C(?=EFG)D          //失败,因为(?=EFG)定位结果是D字符后面、E字符前面
正则表达式5:C(?=DEFG)D        //成功
正则表达式6:CD(?<=AB)          //失败,(?<=AB) 定位结果是B字符后面、C字符前面
正则表达式7:CD(?<=ABCD)      //成功
正则表达式7:(?<=AB)CD           //成功

终极示例是这个:
考虑这样一个应用情景:对于一个大的数值,比如35689412,西方国家习惯三位一个量级,中间以逗号隔开,方便一眼看出大小,也即是35,689,412。那么现在有一堆数,请用正则表达式完成替换,替换成诸如35,689,412的格式。题目分析:也就是从右往左数,每隔三个数,如果前面还有数的话就在前面加个逗号。也就是找到这些特定的位置,在该位置处加上“,”。

正则表达式8:(?<=\d)(?=(\d{3})+$)

正则表达式8全由环视结构组成,没有匹配任何字符(如果用group()函数看的话,结果是多个空字符串),但是却匹配了一堆位置。再用:replaceAll(",”),即可完成问题要求。

逆向环视时,pattern长度必须是固定的

有一点需要注意:逆向环视时,pattern长度必须是固定的,也就是说pattern中不能出现诸如*.等这类字符使得pattern匹配的长度不固定;但是前向环视没有这个要求。

(?:pattern)

(?:pattern)则跟环视根本就不是一类东西,只是长得比较像,他们的最大区别就是:(?:pattern)是匹配文字,也就是会消耗字符。比如将正则表达式3做如下修改:

正则表达式3_1:CD(?:EF)G

改成(?:EF)后,匹配成功。(?:pattern)是和(pattern)相对应的,他们的区别在于:(pattern)是获取匹配,pattern内容会出现在匹配结果的集合中;(?:pattern)是非获取匹配。

你可能感兴趣的:(JAVA学习笔记)