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*
分享到:
评论