`
yysct2005
  • 浏览: 90612 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Java 正则表达式全攻略(六)

    博客分类:
  • java
阅读更多

Java 正则表达式全攻略(六)

[ 2010-04-23 12:47:00.0 | 作者: 随想 类别: 基础强化 ] 来源:网络收集     浏览 1383
labels:Java 正则表达式全攻略(六) java正则表达式 向前查看 向后查看

零宽断言

Perl 5 引入了两个强大的正则语法:“向前查看”和“向后查看”。他们也被称作“零长度断言”。他们和锚定一样都是零长度的(所谓零长度即指该正则表达式不消耗被 匹配的字符串)。不同之处在于“前后查看”会实际匹配字符,只是他们会抛弃匹配只返回匹配结果:匹配或不匹配。这就是为什么他们被称作“断言”。他们并不 实际消耗字符串中的字符,而只是断言一个匹配是否可能。(ps:现在几乎所有正则表达式引擎的实现都支持“向前和向后查看”,不过Javascript只 支持向前查看。)

语法 说明
(?=X) 肯定式向前查看,X代表查看的表达式
(?!X) 否定式向前查看,X代表查看的表达式
(?<=X) 肯定式向后查看,X代表查看的表达式
(? 否定式向后查看,X代表查看的表达式

?

向前查看

(?=X) 代表肯定式的向前查看,在任何匹配 Pattern 的字符串开始处匹配查找 X 表达式所代表的字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。这估计还是太难理解,还是直接用实例说明,请看下面的代码:

   1:


 Pattern p = Pattern.compile("Windows(?=NT|2000|2003)"
);

   2:


 Matcher m1 = p.matcher("WindowsXP"
);

   3:


 assertThat(m1.find(), is(false));

   4:


 Matcher m2 = p.matcher("Windows2003"
);

   5:


 assertThat(m2.find(), is(true));

   6:


 assertThat(m2.group(), equalTo("Windows"
));

表达式 Windows(?=NT|2000|2003) 能匹配 Windows2003 中的 Windows,但不能匹配 WindowsXP 中的 Windows,因为我们的表达式声明了它要匹配的 Windows 后面必须跟着 NT 或 2000 又或 2003 。这种查看的断言是不消耗字符的,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含断言的字符之后开始。

如果我们现在把表达式稍作调整,改为 Windows(?!NT|2000|2003) ,这样一来结果就刚好和上面例子的相反。这个时候查看的内容就变为否定式的,在否定式中查看的结果与肯定式相反,如果查看成功将引起整体匹配的失败,而查看失败则匹配成功。

向后查看

与向前查看相反,我们还有向后查看,语法为:(?<=X),它用户限定表达式前必须包含指定的内容。我们还是用一个简单的例子来说明:

   1:


 String string = "dog dog
gie bulldog"
;

   2:


 // 向后查看的内容为 (?<= )


   3:


 Pattern p = Pattern.compile("(?<= )dog"
);

   4:


 Matcher m = p.matcher(string);

   5:


 assertThat(m.find(), is(true));

   6:


 assertThat(m.group(), equalTo("dog"
));

   7:


 assertThat(m.start(), is(4));

   8:


 assertThat(m.end(), is(7));

我们可以看到当我们声明了向后查看 (?< ) 后,我们找到的内容仅为红色的 dog 部分,我们可以从它的工作方式来理解一下。在刚开始匹配时,表达式引擎先向后查看一下有没有空格字符。由于现在在开始位置,前面没有内容,所以查看失败, 直接跳过第一个d开始查看o,o前面也没有空格,所以也失败进入下个字符。知道到第二个d,这时候向后查看成功了,后续的表达式也匹配成功,因此返回了匹 配结果。

同向前查看一样,向后查看也有否定式,它的语法为 (?

向前查看和向后查看的应用

我们来看这样一个例子:查找一个具有6位字符的,含有“cat”的单词。首先,我们可以不用向前向后查看来解决问题,例如:cat\w{3}|\wcat\w{2}|\w{2}cat\w|\w{3}cat 很麻烦吧!
接下来再让我们来看看使用向前查看的方案。在这个例子中,我们有两个基本需求要满足:一是我们需要一个6位的字符,二是单词含有“cat”。满足第一个需求的正则表达式为 \b\w{6}\b 。满足第二个需求的正则表达式为 \b\w*cat\w*\b 。把两者结合起来,我们可以得到如下的正则表达式:(?=\b\w{6}\b)\b\w*cat\w*\b
具体的匹配过程留给读者。但是要注意的一点是,向前查看是不消耗字符的,因此当判断单词满足具有6个字符的条件后,引擎会从开始判断前的位置继续对后面的正则表达式进行匹配。最后作些优化,可以得到下面的正则表达式: \b(?=\w{6}\b)\w{0,3}cat\w*

分享到:
评论
Global site tag (gtag.js) - Google Analytics