宝哥软件园

反过来看正则性的应用

编辑:宝哥软件园 来源:互联网 时间:2021-10-08

1这个问题导致前几天在CSDN论坛上遇到这样一个问题。我想通过正则化提取font color='#008000 '和/font之间的以下字符串。1.font color='#008000 '和/font之间的字符串不能固定,是随机自动生成的。2.字体颜色='#008000 '和/font的数量也不能固定。它也是随机自动生成的font color='#008000' **这里是不固定字符串1 ** /font font color='#008000' **这里是不固定字符串2 ** /font font color='#008000' **这里是不固定字符串3 ** /font。=font[sS]*?)([sS]*?)(?=/font)",看匹配结果。复制的代码如下: string test=@ ' font color=' ' # 008000 ' ' * *这里是未固定的字符串1 * */font font color=' ' # 008000 ' ' * *这里是未固定的字符串2 * */font font color=' ' # 008000 ' ' * *。MatchCollection mc=Regex。匹配(测试,@ '(?=font[sS]*?)([sS]*?)(?=/font)');foreach(MC中的Match m){ richtextbox 2。文本=m .值' n- n ';}/* -这里是不固定的字符串1 * * - font color=' # 008000' * *这里是不固定的字符串2 * * -。/* *-输出* *这里是不固定的字符串1 * *-* *这里是不固定的字符串2 * *-。2逆序环视的匹配原则——《定期环视》的博客中已经介绍了一些基本的讲解和环视的基本匹配原则,但当时安排的比较匆忙,没有涉及到更详细的匹配细节。这个讨论只是为了反过来看看。逆序环视的基本知识已经在上面的博文中介绍过了,这里简单引用一下。表达式描述(?=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}”。

来源:diva测试/div需求:获取div标签的内容,不包括div标签本身的Java代码实现:复制代码如下:导入Java . util . regex . *;字符串测试='diva测试/div ';字符串reg='(?=div)[^](?=/div)';Matcher m=Pattern.compile(reg)。匹配器(测试);while(m . find()){ system . out . println(m . group());}/* -一个test */但是如果源字符串发生了变化,一个属性变成了“div id=" test1 " -一个test/div”,那么除非标签中的属性内容是固定的,否则在Java中是无法通过倒序查找来实现的。为什么很多流行语言要么不支持逆序查找,要么只支持定长子表达式?我们来分析一下逆序环视的匹配原则。2 . 1 . 2 Java中反向lookup匹配原理分析不言而喻,它不支持反向lookup,只支持定长子表达式的反向lookup。来源:diva测试/div正则表达式:(?=div)[^](?=/div)

明确一点,无论是哪种正则表达式,都要从字符串的位置0开始尝试匹配。先通过”(?=div”),并尝试从位置0开始匹配。由于“div”的长度固定为5,它将从当前位置向左查找5个字符。但是,由于此时它位于位置0,并且前面没有字符,因此匹配尝试失败。常规发动机传动装置向右行驶,试图从位置1匹配,但也未能匹配到位置5,向左寻找5个字符,满足条件,然后将控制权交给“(?=div)”,子表达式“div”。在“div”获得控制权后,它试图从位置0向右匹配。由于正则化是逐字符的,所以它会将控制权交给“div”中的“”和字符串中的“”将尝试“”,然后字符串中的“d”将尝试成功匹配。在同一过程中,“div”将位置0与位置匹配。=div)"匹配成功,匹配成功的位置为位置5。以下匹配过程请参考定期——环视和定期——NFA引擎匹配原则。所以对于量词”?“是什么样的情况?看看下面的例子。来源:cba正则表达式:(?=(c?b))一份副本代码如下: String test=' cba字符串reg='(?=(c?b))a ';Matcher m=Pattern.compile(reg)。匹配器(测试);while(m . find()){ system . out . println(m . group());system . out . println(m . group(1));}/*-输出-A */可以看到,“C?“没有参与匹配,在这里,”?“它没有贪婪模式的功能。只提供一个分支的功能,记录两个分支。一个分支需要从当前位置向前看一个字符,另一个分支需要从当前位置向前看两个字符。从目前的位置来看,常规引擎尝试这两种情况。第一种尝试是向前寻找字符较少的分支。如果匹配成功,则不会尝试另一个分支。只有当这个分支匹配失败时,它才会尝试另一个分支。复制的代码如下: String test=' dcba字符串reg='(?=(dc?b))a ';Matcher m=Pattern.compile(reg)。匹配器(测试);while(m . find()){ system . out . println(m . group());system . out . println(m . group(1));}/*-Output-A DCB */虽然有两个分支,但是向前搜索的字符数是可以预测的,所以只有“?”是受支持的。并不复杂,但是如果支持其他不定长的量词呢?2.1.3 .NET中逆序查找的匹配原则。NET。按照相反的顺序环顾四周,支持不定长的量词。此时,匹配过程变得复杂。让我们看看固定长度是如何匹配的。复制的代码如下:字符串测试='diva测试/div ';Regex reg=新Regex(@ '(?=div)[^](?=/div)');匹配m=reg。匹配(测试);如果(m .成功){ richTextBox2。文本=m .值' n ';}/* -一个测试*/从结果中,我们可以看到当子表达式长度固定在。NET中,匹配行为应该与Java中的行为相同。那么不定量词呢?复制的代码如下:字符串测试=' cbaRegex reg=新Regex(@ '(?=(c?b))a’;匹配m=reg。匹配(测试);如果(m .成功){ richTextBox2。文本=m .值' n ';richTextBox2。文本=m组[1]。值' n ';}/*-输出-A CB */如你所见,这里是“?".具有贪婪模式的特点。这时,匹配过程是从当前位置向左尝试还是从字符串开头向右尝试,还有疑问吗?复制的代码如下:字符串测试=' dddcccbaRegex reg=新Regex(@ '(?=(.*?b))a’;匹配m=reg。匹配(测试);如果(m .成功){ richTextBox2。文本=m .值' n ';richTextBox2。文本=m组[1]。值' n ';}/* - a cccb */从结果中我们可以看到,当存在逆序的不定量词时,我们还是尽量从当前位置向左匹配,否则,Groups[1]的内容就是“dddcccb”而不是“cccb”。

这是非贪婪模式的匹配。让我们看看贪婪模式的匹配。复制的代码如下:字符串测试=' edddcccbaRegex reg=新Regex(@ '(?=(.* b))a’;匹配m=reg。匹配(测试);如果(m .成功){ richTextBox2。文本=m .值' n ';richTextBox2。文本=m组[1]。值' n ';}/* - a dddcccb */可以看出,采用贪婪模式后,虽然“c”前面的“”可以成功匹配,但由于贪婪模式,仍然需要继续尝试匹配。直到你尝试到起始位置,以最长的成功匹配作为匹配结果。2.2匹配过程我们倒过来看看匹配过程。来源:div id="test1" a test/div正则表达式:(?=div[^]*)[^](?=/div)

先通过”(?=div [] *)”,并尝试从位置0开始匹配。因为“div [] *”的长度不固定,所以会从当前位置开始逐字符向左搜索。当然也有可能是常规引擎已经优化了,然后计算出最小长度后会向前搜索。这里“div [] *”至少需要5个字符,所以会从当前位置向左搜索。但是由于此时它位于位置0,前面没有字符,所以尝试匹配失败。常规发动机传动装置向右行驶,试图从位置1匹配,但也未能匹配到位置5,向左寻找5个字符,满足条件,然后将控制权交给“(?=div [] *),“div [] *”。在“div [] *”获得控制权后,它试图从位置0向右匹配。由于规则匹配是逐字符进行的,所以在“div [] *”中控件将被赋予“”,在字符串中“”将尝试“”,匹配将成功。然后,“d”会在字符串中尝试“d”,匹配就会成功。当“] *”与“div”中的空格匹配时,需要记录可追溯的状态。此时,控制权交给了“”。由于没有要匹配的字符,“”匹配失败。此时进行回溯,将匹配的空格“] *”放弃为“”进行匹配。同样,匹配失败。此时没有可以追溯的状态,所以这一轮。常规发动机传动装置向右行驶,并试图从位置6匹配,但直到位置16也无法匹配。此时,当前位置指的是位置16,并赋予控制权“(?=div [] *)”,向左找5个字符,满足条件,记录回溯状态,控制权给”(?=div [] *),“div [] *”。“div [] *”获得控制权后,试图从位置11向右匹配,“div [] *”中的“”试图在字符串中“s”,匹配失败。继续向左尝试,在第10个位置用“”尝试字符串中的“e”,匹配失败。在同一个过程中,直到尝试定位0,“div [] *”尝试在位置0匹配到右边,并成功匹配到“div id="test1”。这时,“(?=div [] *)”,控制权交给“[]”,后续匹配一直持续到整个表达式匹配成功。总结一下正则表达式“(?=SubExP 1)SubExP 2: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 ' ' * *。MatchCollection mc=Regex。匹配(测试,@ '(?=font[sS]*?)([sS]*?)(?=/font)');foreach(MC中的Match m){ richtextbox 2。文本=m .值' n- n ';}/* -这里是不固定的字符串1 * * - font color=' # 008000' * *这里是不固定的字符串2 * * -。*-*/其实真正让人不解的是这里倒序看的匹配结果。为了更好地解释问题,改变规律性。Test=@' fontcolor='' # 008000'' * *这是一个未固定的字符串。1 ** /font复制代码如下: font color=''#008000'' **这里是一个不固定的字符串。2 * */font font color=' ' # 008000 ' ' * *。MatchCollection mc=Regex。匹配(测试,@ '(?=(字体[sS]*?))([sS]*?)(?=/font)');for(int I=0;imc。计数;I) {richTextBox2。Text='在(i 1)'回合中成功匹配的结果: n ';richTextBox2。文本='组[0]:' m .值' n ';richTextBox2。文本='组[1]:' m .组[1]。值' n- n ';}/* - 08000' * *这里是未固定字符串2 * * group[1]:font color=' # 008000 ' * *这里是未固定字符串1 * */font-第三个成功匹配的结果:group [0]: fontcolor=。这里是未固定的字符串3 * *组[1]: font color=' # 008000' * *这里是未固定的字符串2 * */font-/第一轮匹配成功的结果应该没有疑问,这里就不做解释了。第一轮成功匹配在第一个“/font”之前的位置结束,第二轮成功匹配尝试从这个位置开始。先通过”(?=font[sS]*?),找左边6个字符,尽量匹配。因为“”将无法匹配,所以它将始终尝试定位0。这时,“字体”可以匹配成功,但是因为“字体[sS]*?".要匹配成功,匹配的结束位置必须是第一个“/font”之前的位置,所以“”匹配失败,整个表达式在这个位置匹配失败。常规发动机传动装置向右行驶,直到第一个“/font”、“font[sS]*”后面的位置。".匹配成功。匹配开始位置为位置0,匹配结束位置为第一个“/font”、“font[sS]*”后的位置?匹配的内容是“font color='#008000' **这里是未固定的字符串1 ** /font”,其中“sS]*?".匹配的内容为“color='#008000' **这里是未固定的字符串1 ** /font”,后面的子表达式继续匹配,直到第二轮匹配成功。接下来的第三轮匹配成功,匹配过程和第二轮基本一致,只是使用了非贪婪模式,所以“font[sS]*?".当匹配成功到“font color='#008000' **这是未固定的字符串2 ** /font”时,匹配完成,不再尝试向左匹配。接下来看贪婪模式的匹配结果。

复制的代码如下: string test=@ ' font color=' ' # 008000 ' ' * *这里是未固定的字符串1 * */font font color=' ' # 008000 ' ' * *这里是未固定的字符串2 * */font font color=' ' # 008000 ' ' * *。MatchCollection mc=Regex。匹配(测试,@ '(?=(字体[ S S]*)([ S S]*?)(?=/font)');for(int I=0;imc。计数;I) {richTextBox2。Text='在(i 1)'回合中成功匹配的结果: n ';richTextBox2。文本='组[0]:' m .值' n ';richTextBox2。文本='组[1]:' m .组[1]。值' n- n ';}/*-输出-第一轮匹配结果:组[0]: * *这里是未固定的字符串1 * *组[1]: font color=' # 008000'-。这里是未固定字符串2 * * group[1]:font color=' # 008000 ' * *这里是未固定字符串1 * */font-第三轮匹配结果:group [0]: font color=' # 008000 '。Group [1]: font color=' # 008000' * *这里是一个不固定的字符串1 ** /font font color='#008000' **这里是一个不固定的字符串2 * */font-只有一个字符差。那么,如果我们想得到下面的结果,应该怎么做呢?/* *-输出* *这里是不固定的字符串1 * *-* *这里是不固定的字符串2 * *-。复制的代码如下: string test=@ ' font color=' ' # 008000 ' ' * *这里是未固定的字符串1 * */font font color=' ' # 008000 ' ' * *这里是未固定的字符串2 * */font font color=' ' # 008000 ' ' * *。MatchCollection mc=Regex。匹配(测试,@ '(?是()?=(font[^]*))(?(?/?字体b)。)*(?=/font)');for(int I=0;imc。计数;I) {richTextBox2。text=' I ^ 1 '轮的匹配结果: n ';richTextBox2。Text='Group[0]:' mc[i]。值' n ';richTextBox2。Text='Group[1]:' mc[i]。群组[1]。值' n- n ';}/*-输出-第一轮匹配结果:组[0]: * *这里是未固定的字符串1 * *组[1]: font color=' # 008000'-。group [1]: font color=' # 008000'-第三轮匹配结果:group [0]: * *这里是一个未固定的字符串3 * * group[1]:font color=' # 008000 '-。3.2反向回望的应用总结通过对反向回望的分析可以看出,匹配过程复杂,成本非常高,这可能是大多数语言不支持反向回望,或者不支持在反向回望中使用不定量词的原因。在常规应用中需要注意的几点:1 .不要用不定长量词倒序,除非真的需要;2.在任何场景下,不要只是倒着看,不要轻易用量词去修饰匹配范围非常大的子表达式,比如“小数点”。和“[sS]”,使用时要特别注意。

更多资讯
游戏推荐
更多+