格给“>”进行匹配,同样匹配失败,此时已没有可供回溯的状态,所以这一轮匹配尝试失败。
正则引擎传动装置向右传动,由位置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 问题分析
那么再回过头来看下最初的问题。
复制代码 代码如下:
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 **
---------------
*/
其实真正让人费解的是这里的逆序环视的匹配结果,为了更好的说明问题,改下正则。
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>)");
for(int i=0;i<mc.Count;i++)
{
richTextBox2.Text += "第" + (i+1) + "轮成功匹配结果:\n";
richTextBox2.Text += "Group[0]:" + m.Value + "\n";
richTextBox2.Text += "Group:" + m.Groups.Value + "\n---------------\n";
}
/*--------输出--------
第1轮成功匹配结果:
Group[0]: ** 这里是不固定的字符串1 **
Group:<font color="#008000">
---------------
第2轮成功匹配结果:
Group[0]:
<font color="#008000"> ** 这里是不固定的字符串2 **
Group:<font color=