“现代”的正则表达式的认识电源
-
27-10-2019 - |
题
什么类的语言都真正现代的正则表达式实际上承认?
每当有一个向后引用无界长度捕获基团(例如(.*)_\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) | (?"ed_string))
(?<domain> (?&dot_atom) | (?&domain_literal))
(?<domain_literal> (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
\] (?&CFWS)?)
(?<dcontent> (?&dtext) | (?"ed_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) | (?"ed_pair))
(?<quoted_string> (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
(?&FWS)? (?&DQUOTE) (?&CFWS)?)
(?<word> (?&atom) | (?"ed_string))
(?<phrase> (?&word)+)
# Folding white space
(?<FWS> (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
(?<ctext> (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
(?<ccontent> (?&ctext) | (?"ed_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
}
}
正如你看到的,通过在图案采用了非常稍有不同的符号,你现在得到的东西存储整个解析树在%/
变量离开你,什么东西都整齐地标。转换的结果仍然是一个模式,你可以通过=~
操作者看到。它只是有点不可思议。