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

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

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

环视

(?=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)是非获取匹配。

  • 14
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
JavaScript正则表达式和Java正则表达式在语法上有一些差异,但是它们的基本概念和用法是相似的。下面是将JavaScript正则表达式转换为Java正则表达式的一些常见规则: 1. 语法差异: - JavaScript正则表达式使用斜杠(/)作为定界符,而Java正则表达式使用双引号(")作为定界符。 - JavaScript正则表达式中的特殊字符需要进行转义,而Java正则表达式中的特殊字符不需要转义。 2. 字符类: - JavaScript正则表达式中的字符类使用方括号([])表示,而Java正则表达式中使用方括号([])或者Unicode转义(\p{...})表示。 - JavaScript正则表达式中的字符类可以使用连字符(-)表示范围,而Java正则表达式中需要使用Unicode转义(\uXXXX)表示范围。 3. 量词: - JavaScript正则表达式中的量词使用花括号({})表示,而Java正则表达式中使用花括号({})或者问号(?)表示。 - JavaScript正则表达式中的贪婪量词默认是贪婪模式,而Java正则表达式中的贪婪量词需要在后面添加问号(?)来表示非贪婪模式。 4. 边界匹配: - JavaScript正则表达式中的边界匹配使用插入符号(^)和美元符号($)表示,而Java正则表达式中使用\A和\Z表示。 5. 其他差异: - JavaScript正则表达式中的捕获组使用圆括号(())表示,而Java正则表达式中使用圆括号(())或者方括号([])表示。 - JavaScript正则表达式中的反向引用使用反斜杠加数字(\1、\2等)表示,而Java正则表达式中使用美元符号加数字($1、$2等)表示。 以上是一些常见的JavaScript正则表达式转换为Java正则表达式的规则。具体转换时,还需要根据具体的正则表达式进行适当的调整。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值