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


string test = "<ddd<cccba";
Regex reg = new Regex(@"(?<=(<.*?b))a");
Match m = reg.Match(test);
if (m.Success)
{
richTextBox2.Text += m.Value + "\n";
richTextBox2.Text += m.Groups[1].Value + "\n";
}
/*--------输出--------
a
<cccb
*/


从结果可看出,在逆序环视中有不定量词的时候,仍然是从当前位置,向左尝试匹配的,否则Groups[1]的内容就是“<ddd<cccb”,而不是“<cccb”了。
这是非贪婪模式的匹配情况,再看一下贪婪模式匹配的情况。

复制代码 代码如下:


string test = "e<ddd<cccba";
Regex reg = new Regex(@"(?<=(<.*b))a");
Match m = reg.Match(test);
if (m.Success)
{
richTextBox2.Text += m.Value + "\n";
richTextBox2.Text += m.Groups[1].Value + "\n";
}
/*--------输出--------
a
<ddd<cccb
*/


可以看到,采用贪婪模式以后,虽然尝试到“c”前面的“<”时已经可以匹配成功,但由于是贪婪模式,还是要继续尝试匹配的。直到尝试到开始位置,取最长的成功匹配作为匹配结果。
2.2 匹配过程
再来理一下逆序环视的匹配过程吧。
源字符串:<div id=“test1”>a test</div>
正则表达式:(?<=<div[^>]*>)[^<]+(?=</div>)

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



首先由“(?<=<div[^>]*>)”取得控制权,由位置0开始尝匹配,由于“<div[^>]*>”的长度不固定,所以会从当前位置向左逐字符查找,当然,也有可能正则引擎做了优化,先计算一下最小长度后向前查找,在这里“<div[^>]*>”至少需要5个字符,所以由当前位置向左查找5个字符,才开始尝试匹配,这要看各语言的正则引擎如何实现了,我推测是先计算最小长度。但是由于此时位于位置0处,前面没有任何字符,所以尝试匹配失败。

正则引擎传动装置向右传动,由位置1处开始尝试匹配,同样匹配失败,直到位置5处,向左查找5个字符,满足条件,此时把控制权交给“(?<=<div[^>]*>)”中的子表达式“<div[^>]*>”。“<div[^>]*>”取得控制权后,由位置0处开始向右尝试匹配,由于正则都是逐字符进行匹配的,所以这时会把控制权交给“<div[^>]*>”中的“<”,由“<”尝试字符串中的“<”,匹配成功,接下来由“d”尝试字符串中的“d”,匹配成功,同样的过程,由“<div[^>]*”匹配位置0到位置5之间的“<div ”成功,其中“[^>]*”在匹配“<div ”中的空格时是要记录可供回溯的状态的,此时控制权交给“>”,由于已没有任何字符可供匹配,所以“>”匹配失败,此时进行回溯,由“[^>]*”让出已匹配的空格给“>”进行匹配,同样匹配失败,此时已没有可供回溯的状态,所以这一轮匹配尝试失败。

正则引擎传动装置向右传动,由位置6处开始尝试匹配,同样匹配失败,直到位置16处,此时的当前位置指的就是位置16,把控制权交给“(?<=<div[^>]*>)”,向左查找5个字符,满足条件,记录回溯状态,控制权交给“(?<=<div[^>]*>)”中的子表达式“<div[^>]*>”。“<div[^>]*>”取得控制权后,由位置11处开始向右尝试匹配, “<div[^>]*>”中的“<”尝试字符串中的“s”,匹配失败。继续向左尝试,在位置10处由“<”尝试字符串中的“e”,匹配失败。同样的过程,直到尝试到位置0处,由“<div[^>]*”在位置0向右尝试匹配,成功匹配到“<div id=“test1”>”,此时“(?<=<div[^>]*>)”匹配成功,控制权交给“[^>]+”,继续进行下面的匹配,直到整个表达式匹配成功。

总结正则表达式“(?<=SubExp1) SubExp2”的匹配过程:

1、 由位置0处向右尝试匹配,直到找到一个满足“(?<=SubExp1) ”最小长度要求的位置x;
2、 从位置x处向左查找满足“SubExp1”最小长度要求的位置y;
3、 由“SubExp1”从位置y开始向右尝试匹配;
4、 如果“SubExp1”为固定长度或非贪婪模式,则找到一个成功匹配项即停止尝试匹配;
5、 如果“SubExp1”为贪婪模式,则要尝试所有的可能,取最长的成功匹配项作为匹配结果。
6、 “(?<=SubExp1) ”成功匹配后,控制权交给后面的子表达式,继续尝试匹配。

需要说明的一点,逆序环视中的子表达式“SubExp1”,匹配成功时,匹配开始的位置是不可预知的,但匹配结束的位置一定是位置x。

3 问题分析与总结

3.1 问题分析
那么再回过头来看下最初的问题。

复制代码 代码如下:

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

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