正则表达式(三)

数量词/限定符

从前面的例子中,我们可以了解到数量词,是用来指定正则表达式的一个给定字符集必须要出现多少次才能满足匹配。有 * 或 + 或 ? 或 {n} 或 {n,} 或 {n,m} 共6种。每种都有Greedy、Reluctant、Possessive三种匹配方式,Greedy是默认的匹配方式。*、+和?限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个?就可以实现懒惰或最小匹配。不同的匹配方式,对正则表达式的执行方式和性能影响都是十分重要的。

Greedy 贪婪

Greedy量词被看作“贪婪”,因为它们在试图搜索第一个匹配之前读完(或者说吃掉)整个输入字符串。如果第一个匹配尝试(整个输入字符串)失败,匹配器就会在输入字符串中后退一个字符并且再次尝试,重复这个过程,直到找到匹配或者没有更多剩下的字符可以后退为止。以下面代码为例(它的输出结果为“xfooxxxxxxfoo”)。

   1: Pattern p = Pattern.compile(".*foo");
   2: Matcher m = p.matcher("xfooxxxxxxfoo");
   3: while (m.find()) {
   4:     System.out.print(m.group() + "/t");
   5: }

假设你想用一个正则表达式匹配一个HTML标签。你知道输入将会是一个有效的HTML文件,因此正则表达式不需要排除那些无效的标签。所以如果是在两个尖括号之间的内容,就应该是一个HTML标签。 许多正则表达式的新手会首先想到用正则表达式 <.+> ,他们会很惊讶的发现,对于测试字符串,“This is a <EM>first</EM> test”,你可能期望会返回<EM>,然后继续进行匹配的时候,返回</EM>。 但事实是不会。正则表达式将会匹配“<EM>first</EM>”。很显然这不是我们想要的结果。原因在于Greedy(贪婪)是默认的配置方式。也就是说,“+”会导致正则表达式引擎试图尽可能的重复前导字符。只有当这种重复会引起整个正则表达式匹配失败的情况下,引擎会进行回溯。也就是说,它会放弃最后一次的“重复”,然后处理正则表达式余下的部分。

 

Reluctant 懒惰

与Greedy完全相反,Reluctant量词被看作“懒惰”:它们从输入字符串的开头开始,然后逐步地一次读取一个字符搜索匹配。它们最后试图匹配的内容是整个输入字符串。以下面代码为例(它的输出结果为“xfoo    xxxxxxfoo”)。

   1: Pattern p = Pattern.compile(".*?foo");
   2: Matcher m = p.matcher("xfooxxxxxxfoo");
   3: while (m.find()) {
   4:     System.out.print(m.group() + "/t");
   5: }

一个用于修正前面HTML问题的可能方案就是使用惰性代替贪婪性。你可以使用 <.+?> 来完成HTML标签的提取。除此以外可以用一个贪婪重复与一个取反字符集:“ <[^>]+> ”。这是一个更好的方案,它利用了Greedy的特性来提高匹配效率。

Possessive 独占

最后,Possessive量词总是读完整个输入字符串,尝试一次(而且只有一次)匹配。和Greedy量词不同,Possessive从不后退,即使这样做能允许整体匹配成功。继续以代码为例(这次没有任何输出,因为匹配失败)

   1: Pattern p = Pattern.compile(".*+foo");
   2: Matcher m = p.matcher("xfooxxxxxxfoo");
   3: while (m.find()) {
   4:     System.out.print(m.group() + "/t");
   5: }

这种情况下,.*+消耗整个输入字符串,在表达式的结尾没有剩下满足“foo”的内容。Possessive量词用于处理所有内容,但是从不后退的情况;在没有立即发现匹配的情况下,它的性能优于功能相同的Greedy量词。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值