正则应用之 逆序环视探索 .

1 问题引出

前几天在CSDN论坛遇到这样一个问题。
我要通过正则分别取出下面 <font color="#008000"> 与 </font> 之间的字符串

1、在 <font color="#008000"> 与 </font> 之间的字符串是没法固定的,是随机自动生成的
2、其中 <font color="#008000"> 与 </font>的数量也是没法固定的,也是随机自动生成的

<font color="#008000"> ** 这里是不固定的字符串1 ** </font>
<font color="#008000"> ** 这里是不固定的字符串2 ** </font>
<font color="#008000"> ** 这里是不固定的字符串3 ** </font>
有朋友给出这样的正则“(?<=<font[\s\S]*?>)([\s\S]*?)(?=</font>)”,看下匹配结果。

复制代码 代码如下:


string test = @"<font color=""#008000""> ** 这里是不固定的字符串1 ** </font>
<font color=""#008000""> ** 这里是不固定的字符串2 ** </font>
<font color=""#008000""> ** 这里是不固定的字符串3 ** </font> ";
MatchCollection mc = Regex.Matches(test, @"(?<=<font[\s\S]*?>)([\s\S]*?)(?=</font>)");
foreach (Match m in mc)
{
richTextBox2.Text += m.Value + "\n---------------\n";
}
/*--------输出--------
** 这里是不固定的字符串1 **
---------------
<font color="#008000"> ** 这里是不固定的字符串2 **
---------------
<font color="#008000"> ** 这里是不固定的字符串3 **
---------------
*/
为什么会是这样的结果,而不是我们期望的如下的结果呢?
/*--------输出--------
** 这里是不固定的字符串1 **
---------------
** 这里是不固定的字符串2 **
---------------
** 这里是不固定的字符串3 **
---------------
*/


这涉及到逆序环视的匹配原理,以及贪婪与非贪婪模式应用的一些细节,下面先针对逆序环视的匹配细节展开讨论,然后再回过头来看下这个问题。

2 逆序环视匹配原理

关于环视的一些基础讲解和基本匹配原理,在正则基础之——环视这篇博客里已有所介绍,只不过当时整理得比较匆忙,没有涉及更详细的匹配细节。这里仅针对逆序环视展开讨论。
逆序环视的基础知识在上面博文中已介绍过,这里简单引用一下。

表达式

 

说明

 

(?<=Expression)

 

逆序肯定环视,表示所在位置左侧能够匹配Expression

 

(?<!Expression)

 

逆序否定环视,表示所在位置左侧不能匹配Expression

 

对于逆序肯定环视(?<=Expression)来说,当子表达式Expression匹配成功时,(?<=Expression)匹配成功,并报告(?<=Expression)匹配当前位置成功。

对于逆序否定环视(?<!Expression)来说,当子表达式Expression匹配成功时,(?<!Expression)匹配失败;当子表达式Expression匹配失败时,(?<!Expression)匹配成功,并报告(?<!Expression)匹配当前位置成功。

2.1 逆序环视匹配行为分析
2.1.1 逆序环视支持现状
目前支持逆序环视的语言还比较少,比如当前比较流行的脚本语言JavaScript中就是不支持逆序环视的。个人认为不支持逆序环视已成为目前JavaScript中使用正则的最大限制,一些使用逆序环视很轻松搞定的输入验证,却要通过各种变通的方式来实现。

需求:验证输入由字母、数字和下划线组成,下划线不能出现在开始或结束位置。

对于这样的需求,如果支持逆序环视,直接“^(?!_)[a-zA-Z0-9_]+(?<!_)$”就可以了搞定了,但是在JavaScript中,却需要用类似于“^[a-zA-Z0-9]([a-zA-Z0-9_]*[a-zA-Z0-9])?$”这种变通方式来实现。这只是一个简单的例子,实际的应用中,会比这复杂得多,而为了避免量词的嵌套带来的效率陷阱,正则实现起来很困难,甚至有些情况不得不拆分成多个正则来实现。

而另一些流行的语言,比如Java中,虽然支持逆序环视,但只支持固定长度的子表达式,量词也只支持“?”,其它不定长度的量词如“*”、“+” 、“{m,n}”等是不支持的。

源字符串:<div>a test</div>
需求:取得div标签的内容,不包括div标签本身
Java代码实现:

复制代码 代码如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wfyzjx.html