美文网首页
你真的了解正则吗(2)----递归

你真的了解正则吗(2)----递归

作者: RexingLeung | 来源:发表于2020-03-26 11:09 被阅读0次

    [TOC]

    前言

    本文的递归不仅是在JavaScript环境下( 有些匹配操作符JavaScript环境下是不适用的 ) , 在PHP和java环境下 , 也适用
    上一篇文章我们已经简单的介绍了正则的使用和正则匹配规则 , 这篇我们就好好说一下正则的递归

    正则表达式递归

    简单递归

    在各类语言中 , 以下正则的递归操作符都是递归的意思

    • (?R)?
    • (?0)?
    • \g<0>?
    • 加号 , +
    • 星号 *
    • 问号 ? 一般来说问号也是递归的一种
    例子

    比如最简单的 /a+z+/ , 都可以用上面

    • a(?R)?z
    • a(?0)?z
    • a\g<0>?z
    例子正则轨道图

    这里附上/a+z+/的轨道图


    /a+z+/的轨道图.png
    说明

    z全部匹配一个或多个字母a,后跟完全相同数量的字母z。由于这些正则表达式在功能上是相同的,因此我们将使用R的语法进行递归,以查看此正则表达式如何与字符串aaazzz匹配。

    正则引擎实现步骤

    首先,a匹配字符串中的第一个a。然后正则表达式引擎到达(?R)。这告诉引擎在字符串的当前位置再次尝试整个正则表达式。现在,a匹配字符串中的第二个a。发动机再次达到(?R)。在第二个递归上,a匹配第三个a。在第三次递归中,a不能匹配字符串中的第一个z。这导致(?R)失败。但是正则表达式使用量词使(?R)为可选。所以引擎继续z匹配字符串中的第一个z。

    现在,正则表达式引擎已到达正则表达式的末尾。但是,由于递归有两个层次,因此尚未找到整体匹配项。它仅找到了(?R)的匹配项。匹配成功后退出递归,引擎也达到z。现在,它与字符串中的第二个z匹配。引擎的递归深度仍为一级,如果成功,则从该引擎退出。最后,z第三匹配z的的字符串中。引擎再次位于正则表达式的末尾。这次,它不在任何递归内。因此,它返回aaazzz作为整个正则表达式匹配项。

    匹配平衡构造

    递归的主要目的是匹配平衡构造或嵌套构造。通用正则表达式为b(?:m|(?R))*e,其中b是开始构造的地方,m是可能在构造中间出现的东西,e是可能在构造结束时出现的东西。为了获得正确的结果,b,m和e中的任何两个都不能匹配相同的文本。您可以使用原子组而不是非捕获组来提高性能:b(?>m|(?R))*e。现实世界中常见的用法是匹配一组平衡的括号。((?>[^()]|(?R))*)匹配一对括号,中间包含任意文本,包括不限数量的括号,只要它们都正确配对即可。如果主题字符串包含不平衡的括号,则第一个正则表达式匹配项是最左对的平衡括号,这可能发生在不平衡的开括号之后。如果您想要的正则表达式在包含不平衡括号的字符串中找不到任何匹配项,则需要使用子例程调用而不是递归。如果要查找多对平衡括号对的序列作为单个匹配项,则还需要一个子例程调用。

    交替递归

    如果平衡结构中间可能出现的内容也可以单独出现而没有开头和结尾部分,则通用正则表达式为
    b(?R)*e|e|b , 同样b , m 和 e 都必须互斥 . ((?R)*)|[^()]+匹配一对平衡的括号,如上一节中的正则表达式。但是,它也匹配根本不包含任何括号的任何文本。此正则表达式在Boost中无法正常工作。如果某个正则表达式具有不在组内的替换,则在Boost中递归整个正则表达式只会尝试第一种选择。因此((?R)*)|Boost中的[^()]+匹配任意深度嵌套的任意数量的平衡括号,中间没有任何文本,或者根本不包含任何括号的任何文本。如果翻转选项,则[^()]+|((?R)*)在Boost中,任何不带括号的文本都将匹配,或者将一对带括号的文本与任何不带括号的文本匹配。在所有其他版本中,这两个正则表达式找到相同的匹配项。Boost的解决方案是将轮换放到一个组中。(?:((?R)*)|[^()]+)和(?:[^()]+|((?R)*))在本文讨论的所有情景中都找到相同的匹配项本教程支持递归。

    相关文章

      网友评论

          本文标题:你真的了解正则吗(2)----递归

          本文链接:https://www.haomeiwen.com/subject/mabquhtx.html