zoukankan      html  css  js  c++  java
  • 正则表达式如何处理嵌套结构

    1, 正则表达式如何处理嵌套结构

    a.       .net处理嵌套结构的方法

    举例说明:

    问题描述:从before (nope (yes (here) okay) after中匹配得到最大的被”()”包含的文本。即显示红色的部分。

    答案:.net"((?>[^()]+|"((?<DEPTH>)|")(?<-DEPTH>))*(?(DEPTH)(?!))")

            分析:

            (1)"(匹配左括号;")匹配右括号;[^()]+匹配非括号字符串

    (2)(?>.)固化分组,固化分组的作用在于:一旦括号内的子表达式匹配之后,匹配的内容就固定下来,在接下来的匹配过程中不会改变,除非整个固化分组的括号都被弃用,在外部回溯中重新应用。该处使用固化分组的作用在于提高匹配速度。

    (3)DEPTH的使用:DEPTH实际使用了命名捕获的<?>…>,它总是能够匹配成功。正则表达式引擎的回溯堆栈保存了当前匹配成功分组的相关信息,而(?<DEPTH>)跟在"(后,所以它的成功匹配便可以保存"(的个数。跟随在")后的结构(?<-DEPTH>).NET独有的结构,它会在匹配")成功之后去掉最近的”successful DEPTH”标记。如果不存在这样的”successful DEPTH”标记,就会报告失败,整个正则表达式匹配失败:1,每匹配一个"(会把正则表达式保存的当前括号嵌套深度值加12, 每匹配一个")会把正则表达式保存的当前括号嵌套深度值减13, (?(DEPTH)(?!))确保匹配最后的")时,深度为0

    2, 如何使用正则表达式处理句法分析树

    如何使用正则表达式识别一棵类似如下表示的句法分析树?

    (TOP (S (NPB (DT The) (NN question) ) (VP (VBZ remains) (SBAR-A (IN whether) (S-A (NPB (PRP they) ) (VP (MD will) (VP-A (VB be) (ADJP (JJ able) (SG (VP (TO to) (VP-A (VB help) (PUNC. us.) ) ) ) ) ) ) ) ) ) ) )

    答案:"((?>[^()]+|"([^()"s]+"s(?<DEPTH>)|")"s(?<-DEPTH>))*(?(DEPTH)(?!))")

    分析类似。

    3, 使用正则表达式处理句法分析树实例

    a.       使用正则表达式获取所有的叶结点:    "((?<POS>[^()]+)"s(?<Leaf>[^()]+)")

    b.      使用正则表达式获取所有的名词短语NP:

    "(NP"s(?>[^()]+|"([^()"s]+"s(?<DEPTH>)|")"s(?<-DEPTH>))*(?(DEPTH)(?!))")

    c.       使用正则表达式获取满足如下性质的子树

            i.   该子句的标记为SBAR[^()]*

                       ii.      该子句根节点的第一个儿子为一个词性为IN的词。

                      iii.      该子句的第二个儿子为一个子句:使用S[^()]*识别

                     iv.      该子句没有其他的儿子

    (?<Clause>"(S[^() ]*"s(?<INWH>"(IN"s[^()]+")"s)(?<ClauseAfterInWh>"(S[^() ]*"s(?>[^()]+|"([^()"s]+"s(?<DEPTH>)|")"s(?<-DEPTH>))*(?(DEPTH)(?!))")"s)")"s(?#Clause)) 在开发模板引擎时遇到了一个用正则表达式比较难以处理的情况,就是无限级的嵌套结构的匹配。HTML标签就属于这种结构。

        举个具体的例子,下面是我们要匹配的内容:

    1
                2
                3
                4
                5
                
    <x>
                <x></x>
                <y></y>
                </x>
                <x></x>

        在找到用正则匹配无限层嵌套结构的方法之前,我只能绕弯路来实现对无限层嵌套结构的匹配。

        我只能用正则先把每个独立的标签匹配出来,然后用第一个标签名x做参数,逐一的查找匹配出来的每一个独立标签,看看他是否是第一个x对应的闭合标签。

        这种方式得加上判断嵌套层次的代码,还得匹配和循环很多没有用的数据。

        后来我才了解到.NET提供了一个正则表达式的扩展特性,用来帮助处理无限层嵌套结构的匹配。这种特性是.NET特有的,别的编程语言或者平台不一定会有。

        我们都知道正则的匹配组的概念,它的语法是 (?<组名>)。使用这个正则语法我们可以建立一个匹配组。其实这是一个入栈的过程。

        而.NET对正则的匹配组做了一个特殊的支持 (?<-组名>)。使用这个正则语法我们可以将指定组名的最后匹配结果去除。也就是出栈了。

        一个入栈一个出栈,这一入一出就为我们提供了匹配无限层嵌套的可能 :)

        下面举个例子看看怎么实现无限层嵌套的匹配: regex-test2.png

        从图中我们可以看出正则正确的匹配出了最顶层的三个<x></x>结构,而嵌套在第二个<x></x>结构中的标签被当成了结构的内容。这是怎么做到的呢?

        下面是图中的正则,我加入了注释:

    1
                2
                3
                4
                5
                6
                7
                8
                9
                10
                
    <x>
                (?>
                <x>(?<n>)           #在匹配到<x>时,将匹配组n入栈
                |
                </x>(?<-n>)        #在匹配到</x>时,将匹配组n出栈
                |
                (?!<x>|</x>).      #匹配除<x>和</x>以外的其他字符
                )*
                (?(n)(?!))              #如果执行到此处还存在匹配组n,则匹配失败,重新匹配
                </x>

        这段正则中还用到了平时比较少使用到的(?!(name)yes|no)语法,这个语法相当于C语言的if语法,用于做条件判断,之用。上面的正则中我们用它来片段是否存在命名组n,如果存在命名组n,说明标记没有对称闭合,用(?!)断言匹配失败,重新匹配。

        在《Mastering Regular Expressions》中似乎有相关章节提到这种无限层嵌套结构的匹配,不过我手头没这本书。我是从这里学习到这种特殊的正则语法的,大家可以参考下

  • 相关阅读:
    Shiro框架:Failed to deserialize java.lang.Exception: Failed to deserialize问题解决
    Linux系统:CentOS防火墙的各种命令使用
    Linux系统:CentOS下vsftpd的安装配置
    Vue项目启动报错:UnhandledPromiseRejectionWarning: TypeError: loaderContext.getResolve is not a function问题解决
    Minio存储桶:部署存储服务以及设置永久下载链接
    Redis之Bitmaps
    Redis事务与Lua
    Redis Pipeline
    Redis Shell详解
    Redis慢查询
  • 原文地址:https://www.cnblogs.com/0000/p/1453446.html
Copyright © 2011-2022 走看看