本人很喜欢VB.NET正则表达式引擎,在工作中也很喜欢总结关于VB.NET正则表达式的经验教训,下面就这个问题来详细说说吧。
什么是正则表达式
基本说来,正则表达式是一种用来描述一定数量文本的模式。Regex代表RegularExpress。本文将用 <
向前查看与向后查看
Perl5引入了两个强大的正则语法:“向前查看”和“向后查看”。他们也被称作“零长度断言”。他们和锚定一样都是零长度的(所谓零长度即指该正则表达式不消耗被匹配的字符串)。不同之处在于“前后查看”会实际匹配字符,只是他们会抛弃匹配只返回匹配结果:匹配或不匹配。这就是为什么他们被称作“断言”。他们并不实际消耗字符串中的字符,而只是断言一个匹配是否可能。几乎本文讨论的所有正则表达式的实现都支持“向前向后查看”。唯一的一个例外是Javascript只支持向前查看。
肯定和否定式的向前查看如我们前面提过的一个例子:要查找一个q,后面没有紧跟一个u。也就是说,要么q后面没有字符,要么后面的字符不是u。采用否定式向前查看后的一个解决方案为 < > 。否定式向前查看的语法是 < <(?!查看的内容)> > 。肯定式向前查看和否定式向前查看很类似: < <(?=查看的内容)> > 。如果在“查看的内容”部分有组,也会产生一个向后引用。但是向前查看本身并不会产生向后引用,也不会被计入向后引用的编号中。这是因为向前查看本身是会被抛弃掉的,只保留匹配与否的判断结果。如果你想保留匹配的结果作为向后引用,你可以用 < <(?=(regex))> > 来产生一个向后引用。
肯定和否定式的先后查看向后查看和向前查看有相同的效果,只是方向相反否定式向后查看的语法是: < <(? > 肯定式向后查看的语法是: < <(? <=查看内容)> > 我们可以看到,和向前查看相比,多了一个表示方向的左尖括号。例: < <(? > 将会匹配一个没有“a”作前导字符的“b”。值得注意的是:向前查看从当前字符串位置开始对“查看”正则表达式进行匹配;向后查看则从当前字符串位置开始先后回溯一个字符,然后再开始对“查看”正则表达式进行匹配。
深入VB.NET正则表达式引擎内部让我们看一个简单例子。把正则表达式 < > 应用到字符串“Iraq”。正则表达式的第一个符号是 <
> 。正如我们知道的,引擎在匹配 <
> 以前会扫过整个字符串。当第四个字符“q”被匹配后,“q”后面是空字符(void)。而下一个正则符号是向前查看。引擎注意到已经进入了一个向前查看正则表达式部分。下一个正则符号是 < > ,和空字符不匹配,从而导致向前查看里的正则表达式匹配失败。因为是一个否定式的向前查看,意味着整个向前查看结果是成功的。于是匹配结果“q”被返回了。我们在把相同的正则表达式应用到“quit”。 <
> 匹配了“q”。下一个正则符号是向前查看部分的 < > ,它匹配了字符串中的第二个字符“i”。引擎继续走到下个字符“i”。然而引擎这时注意到向前查看部分已经处理完了,并且向前查看已经成功。于是引擎抛弃被匹配的字符串部分,这将导致引擎回退到字符“u”。因为向前查看是否定式的,意味着查看部分的成功匹配导致了整个向前查看的失败,因此引擎不得不进行回溯。最后因为再没有其他的“q”和 <
> 匹配,所以整个匹配失败了。为了确保你能清楚地理解向前查看的实现,让我们把 <
> 应用到“quit”。 <
> 首先匹配“q”。然后向前查看成功匹配“u”,匹配的部分被抛弃,只返回可以匹配的判断结果。引擎从字符“i”回退到“u”。由于向前查看成功了,引擎继续处理下一个正则符号 < > 。结果发现 < > 和“u”不匹配。因此匹配失败了。由于后面没有其他的“q”,整个正则表达式的匹配失败了。
更进一步理解VB.NET正则表达式引擎内部机制让我们把 < <(? <=a)b> > 应用到“thingamabob”。引擎开始处理向后查看部分的正则符号和字符串中的第一个字符。在这个例子中,向后查看告诉VB.NET正则表达式引擎回退一个字符,然后查看是否有一个“a”被匹配。因为在“t”前面没有字符,所以引擎不能回退。因此向后查看失败了。引擎继续走到下一个字符“h”。再一次,引擎暂时回退一个字符并检查是否有个“a”被匹配。结果发现了一个“t”。向后查看又失败了。向后查看继续失败,直到正则表达式到达了字符串中的“m”,于是肯定式的向后查看被匹配了。因为它是零长度的,字符串的当前位置仍然是“m”。下一个正则符号是 < > ,和“m”匹配失败。下一个字符是字符串中的第二个“a”。引擎向后暂时回退一个字符,并且发现 < > 不匹配“m”。在下一个字符是字符串中的第一个“b”。引擎暂时性的向后退一个字符发现向后查看被满足了,同时 < > 匹配了“b”。因此整个正则表达式被匹配了。作为结果,正则表达式返回字符串中的第一个“b”。
向前向后查看的应用我们来看这样一个例子:查找一个具有6位字符的,含有“cat”的单词。首先,我们可以不用向前向后查看来解决问题,例如: <
【编辑推荐】