A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 隋营营 于 2012-5-4 17:20 编辑

正在研究正则表达式,碰到了一个让人恶心的问题:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Testext {
    public static void main(String[] args) {
        Pattern pn = Pattern.compile( ".{3}(?=a)" );
        Matcher mr = pn.matcher( "521a88b" );
        while (mr.find()) {
            System.out.println(mr.group());
        }
    }
}
输出:521 (我理解为:结尾的是a,不在3个字符内
将红色部分改为:"(?=a).{3}" 输出:a88 (我理解为:开头是a,在3个字符以内
将红色部分改为:"
(?!a).{3}" 输出:521 88b (我理解为:开头的不能是a
将红色部分改为:".{3}(?!a)" 输出:21a  88b(我理解为:结尾字符不能是a)

可是我将红色部分改为:".{3}(?<!a)" 或"(?<!a).{3}" 后却输出了:521  a88  实在是理解不了!
who can help me? 要崩溃了!

6 个回复

正序浏览
徐晓磊 发表于 2012-5-3 17:53
比如.{3}(?=X) 就是说从这个表达式符合的三个任意字符后开始匹配非捕获组
而.{3}(? ...

thank you
回复 使用道具 举报
比如.{3}(?=X) 就是说从这个表达式符合的三个任意字符后开始匹配非捕获组
而.{3}(?<=X)则是从三个字符前面匹配非捕获组
你在网上搜 java 非捕获组  有很多文章 你看看就明白了 说起来我的表达能力不行
回复 使用道具 举报
徐晓磊 发表于 2012-5-3 17:35
不是对整个字符串进行从后向前的匹配和捕获是针对正则表达式而言的

也许是我表述不准确,应该是拿字符串支匹配正则表达式。
回复 使用道具 举报
隋营营 发表于 2012-5-3 15:13
ok,有点明白了。
.{3}(?

不是对整个字符串进行从后向前的匹配和捕获是针对正则表达式而言的
回复 使用道具 举报
徐晓磊 发表于 2012-5-3 14:45
首先,给你提出一个建议,不能从表面去理解一个语法的规则,像是正则表达式你就该就看api文档的官方解释。
...

ok,有点明白了。
.{3}(?<!a) 和 (?<!a).{3}  表示:从后向前不是a 的进行匹配
前3个字符是521,匹配!a88的前面也不是a,所以匹配!

拓展一下: .{3}(?<=a) 表示从后向前是a且包含a的匹配 输出:21a
(?<=a).{3} 则是从后向前是a但不包含a的匹配 输出:88b
你认为正确吗?
回复 使用道具 举报
本帖最后由 徐晓磊 于 2012-5-3 14:52 编辑

首先,给你提出一个建议,不能从表面去理解一个语法的规则,像是正则表达式你就该就看api文档的官方解释。
1.  ".{3}(?=a)"   这个正则表达式和你下面使用的都是非捕获组的使用。
     意思是有三个任意的字符,并且后跟一个字符a ,注意了 这个字符a并不会捕获,只是用来匹配。这就是非捕获组的意义。
    因此对于字符串521a88b来说第一次匹配时候截取521a,因为满足表达式,所以匹配成功,但是这个最后面的a不进行捕获,只捕获521。
    由于521a已经匹配成功了,接着第二次匹配,注意:第二次匹配时从a开始的,因为a并没有捕获,只是进行匹配使用。所以截取a88b
    由于不符合表达式,所以匹配不成功。继续截取88b,不匹配。
    如果将字符串改为521a88a和521a88ba进行试验,你就会发现它的运行机制。
234的分析第一个一样
3.这个时候的表达式与第一个和第二个第三个都不一样了。因为(?=X)与(?!=X)都是从这个费捕获组的前面的字符的后面开始匹配。
  而(?<=X)和(?<!X)是从这个非捕获组的前面的字符的前面开始匹配的。
  比如.{3}(?=a)是表示有三个字符这三个字符的后面是a
  而.{3}(?<!a) 表示的是有三个字符的前面的空隙是a,注意了对你的字符串来说对于这个表达式,其中的子字符串521的前面没有出现a符合了非捕获组,也就是5符合不是a的条件,但是5不进行匹配,所以不向下,继续从当前位置匹配3个字符,得到了521.继续截取了字符串a88 a的前面是1并不是a所以符合捕获,又应为a已经在第一次匹配中匹配了,所以从a开始进行匹配,得到三个字符a88


如果还是没有看懂就发消息加q
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马