什么类的语言都真正现代的正则表达式实际上承认?

每当有一个向后引用无界长度捕获基团(例如(.*)_\1)一个正则表达式现在匹配的非正则语言。但是,这,就其本身而言是不够的,匹配类似S ::= '(' S ')' | ε - 括号的匹配对上下文无关语言

递归正则表达式(这是新的给我,但我在Perl和PCRE放心存在)似乎承认至少大部分的节能灯。

有没有人做过或阅读这方面的任何研究吗?什么是这些“现代”正则表达式的限制?难道他们承认确实更严格或小于CFGS,LL或LR语法?或者说存在可以通过正则表达式来识别,但两种语言不是一个CFG的的相反?

链接到有关的文件,将不胜感激。

有帮助吗?

解决方案

图案递归

使用递归模式,你有递归下降一种形式的匹配

这是对各种各样的问题很好,但一旦你要真正做递归下降的解析的,你需要在这里插入捕获组和那里,它是尴尬的收回全部解析结构通过这种方式。达米安康威的正则表达式语法:: 模块Perl的变换简单图案形成等价自动执行所有名为捕获到递归数据结构,使得对于所解析的结构的更容易检索。我有这两种方法在此张贴端进行比较的样品。

上递归

限制

现在的问题是什么样的语法递归模式无法比拟的。那么,他们肯定递归下降类型的匹配。我想到的唯一的事情是,递归模式不能处理左递归这使得约束的各种语法,你可以将它们应用到。有时候,你可以重新排列你的作品,以消除左递归。

BTW,PCRE和Perl你如何允许短语递归略有不同。见“RECURSIVE PATTERNS”,并在 pcrepattern 手册页“从Perl的递归差”的章节。例如:Perl可以处理^(.|(.)(?1)\2)$其中PCRE要求^((.)(?1)\2|.)$代替

递归演示

在需要递归模式产生令人惊讶地频繁。参观一个很好的例子是,当你需要匹配的东西,可以窝,如平衡括号,报价,甚至HTML / XML标记。这里的匹配balenced的括号:

\((?:[^()]*+|(?0))*\)

我觉得棘手,因为它的紧凑性阅读。这与/x模式容易固化,使空白不再显著:

\( (?: [^()] *+ | (?0) )* \)

话又说回来,因为我们使用的括号为我们的递归,更清晰的例子是匹配嵌套的单引号:

‘ (?: [^‘’] *+ | (?0) )* ’

您可能希望匹配的另一递归定义的事情是回文。这个简单的图案在Perl的工作原理:

^((.)(?1)\2|.?)$

它可以在大多数系统使用这样的测试:

$ perl -nle 'print if /^((.)(?1)\2|.?)$/i' /usr/share/dict/words

请注意PCRE的实现递归的要求更精细

^(?:((.)(?1)\2|)|((.)(?3)\4|.))

这是因为关于如何PCRE递归作品的限制。

正确解析

对于我来说,上面的例子大多是玩具比赛,并不是所有的的有趣,真的。当它变得有趣的是,当你有你试图解析一个真正的语法。例如,RFC 5322定义,而精心邮件地址。这里的一个“语法”模式来匹配它:

$rfc5322 = qr{

   (?(DEFINE)

     (?<address>         (?&mailbox) | (?&group))
     (?<mailbox>         (?&name_addr) | (?&addr_spec))
     (?<name_addr>       (?&display_name)? (?&angle_addr))
     (?<angle_addr>      (?&CFWS)? < (?&addr_spec) > (?&CFWS)?)
     (?<group>           (?&display_name) : (?:(?&mailbox_list) | (?&CFWS))? ; (?&CFWS)?)
     (?<display_name>    (?&phrase))
     (?<mailbox_list>    (?&mailbox) (?: , (?&mailbox))*)

     (?<addr_spec>       (?&local_part) \@ (?&domain))
     (?<local_part>      (?&dot_atom) | (?&quoted_string))
     (?<domain>          (?&dot_atom) | (?&domain_literal))
     (?<domain_literal>  (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
                                   \] (?&CFWS)?)
     (?<dcontent>        (?&dtext) | (?&quoted_pair))
     (?<dtext>           (?&NO_WS_CTL) | [\x21-\x5a\x5e-\x7e])

     (?<atext>           (?&ALPHA) | (?&DIGIT) | [!#\$%&'*+-/=?^_`{|}~])
     (?<atom>            (?&CFWS)? (?&atext)+ (?&CFWS)?)
     (?<dot_atom>        (?&CFWS)? (?&dot_atom_text) (?&CFWS)?)
     (?<dot_atom_text>   (?&atext)+ (?: \. (?&atext)+)*)

     (?<text>            [\x01-\x09\x0b\x0c\x0e-\x7f])
     (?<quoted_pair>     \\ (?&text))

     (?<qtext>           (?&NO_WS_CTL) | [\x21\x23-\x5b\x5d-\x7e])
     (?<qcontent>        (?&qtext) | (?&quoted_pair))
     (?<quoted_string>   (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
                          (?&FWS)? (?&DQUOTE) (?&CFWS)?)

     (?<word>            (?&atom) | (?&quoted_string))
     (?<phrase>          (?&word)+)

     # Folding white space
     (?<FWS>             (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
     (?<ctext>           (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
     (?<ccontent>        (?&ctext) | (?&quoted_pair) | (?&comment))
     (?<comment>         \( (?: (?&FWS)? (?&ccontent))* (?&FWS)? \) )
     (?<CFWS>            (?: (?&FWS)? (?&comment))*
                         (?: (?:(?&FWS)? (?&comment)) | (?&FWS)))

     # No whitespace control
     (?<NO_WS_CTL>       [\x01-\x08\x0b\x0c\x0e-\x1f\x7f])

     (?<ALPHA>           [A-Za-z])
     (?<DIGIT>           [0-9])
     (?<CRLF>            \x0d \x0a)
     (?<DQUOTE>          ")
     (?<WSP>             [\x20\x09])
   )

   (?&address)

}x;

如你所见,这是非常BNF样。问题是,这只是一个比赛,不是一个捕获。而你真的不希望只是围绕整个事情与捕获的括号,因为这并没有告诉你哪些产品匹配哪个部分。使用前面提到的正则表达式语法::模块,我们可以。

#!/usr/bin/env perl

use strict;
use warnings;
use 5.010;
use Data::Dumper "Dumper";

my $rfc5322 = do {
    use Regexp::Grammars;    # ...the magic is lexically scoped
    qr{

    # Keep the big stick handy, just in case...
    # <debug:on>

    # Match this...
    <address>

    # As defined by these...
    <token: address>         <mailbox> | <group>
    <token: mailbox>         <name_addr> | <addr_spec>
    <token: name_addr>       <display_name>? <angle_addr>
    <token: angle_addr>      <CFWS>? \< <addr_spec> \> <CFWS>?
    <token: group>           <display_name> : (?:<mailbox_list> | <CFWS>)? ; <CFWS>?
    <token: display_name>    <phrase>
    <token: mailbox_list>    <[mailbox]> ** (,)

    <token: addr_spec>       <local_part> \@ <domain>
    <token: local_part>      <dot_atom> | <quoted_string>
    <token: domain>          <dot_atom> | <domain_literal>
    <token: domain_literal>  <CFWS>? \[ (?: <FWS>? <[dcontent]>)* <FWS>?

    <token: dcontent>        <dtext> | <quoted_pair>
    <token: dtext>           <.NO_WS_CTL> | [\x21-\x5a\x5e-\x7e]

    <token: atext>           <.ALPHA> | <.DIGIT> | [!#\$%&'*+-/=?^_`{|}~]
    <token: atom>            <.CFWS>? <.atext>+ <.CFWS>?
    <token: dot_atom>        <.CFWS>? <.dot_atom_text> <.CFWS>?
    <token: dot_atom_text>   <.atext>+ (?: \. <.atext>+)*

    <token: text>            [\x01-\x09\x0b\x0c\x0e-\x7f]
    <token: quoted_pair>     \\ <.text>

    <token: qtext>           <.NO_WS_CTL> | [\x21\x23-\x5b\x5d-\x7e]
    <token: qcontent>        <.qtext> | <.quoted_pair>
    <token: quoted_string>   <.CFWS>? <.DQUOTE> (?:<.FWS>? <.qcontent>)*
                             <.FWS>? <.DQUOTE> <.CFWS>?

    <token: word>            <.atom> | <.quoted_string>
    <token: phrase>          <.word>+

    # Folding white space
    <token: FWS>             (?: <.WSP>* <.CRLF>)? <.WSP>+
    <token: ctext>           <.NO_WS_CTL> | [\x21-\x27\x2a-\x5b\x5d-\x7e]
    <token: ccontent>        <.ctext> | <.quoted_pair> | <.comment>
    <token: comment>         \( (?: <.FWS>? <.ccontent>)* <.FWS>? \)
    <token: CFWS>            (?: <.FWS>? <.comment>)*
                             (?: (?:<.FWS>? <.comment>) | <.FWS>)

    # No whitespace control
    <token: NO_WS_CTL>       [\x01-\x08\x0b\x0c\x0e-\x1f\x7f]
    <token: ALPHA>           [A-Za-z]
    <token: DIGIT>           [0-9]
    <token: CRLF>            \x0d \x0a
    <token: DQUOTE>          "
    <token: WSP>             [\x20\x09]
    }x;
};

while (my $input = <>) {
    if ($input =~ $rfc5322) {
        say Dumper \%/;       # ...the parse tree of any successful match
                              # appears in this punctuation variable
    }
}

正如你看到的,通过在图案采用了非常稍有不同的符号,你现在得到的东西存储整个解析树在%/变量离开你,什么东西都整齐地标。转换的结果仍然是一个模式,你可以通过=~操作者看到。它只是有点不可思议。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top