- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
真正的现代正则表达式实际上可以识别什么类型的语言?
只要存在带有反向引用的无限长度捕获组(例如 (.*)_\1
),正则表达式现在就会匹配非常规语言。但这本身不足以匹配 S::= '(' S ')' | 之类的内容。 ε
— 匹配括号对的上下文无关语言。
递归正则表达式(这对我来说是新的,但我确信 Perl 和 PCRE 中存在)似乎至少可以识别大多数 CFL。
有人做过或阅读过该领域的研究吗?这些“现代”正则表达式有哪些限制?它们对 LL 或 LR 语法的识别严格程度比 CFG 严格多还是严格少?或者是否存在两种语言都可以被正则表达式识别,但 CFG 不能识别和相反的语言?
相关论文的链接将不胜感激。
最佳答案
通过递归模式,您可以得到一种递归下降匹配的形式。
这对于各种问题来说都很好,但是一旦你想要真正进行递归下降解析,你需要到处插入捕获组,并且恢复完整的解析结构是很尴尬的这样。达米安·康威的Regexp::Grammars Perl 的模块将简单模式转换为等效模式,自动将所有命名捕获转换为递归数据结构,从而更轻松地检索已解析的结构。我在本文末尾有一个比较这两种方法的示例。
问题是递归模式可以匹配什么类型的语法。嗯,他们当然是recursive descent类型匹配器。唯一想到的是递归模式无法处理 left recursion . 这对您可以应用它们的语法类型施加了限制。有时您可以重新排序您的产品以消除左递归。
顺便说一句,PCRE 和 Perl 在如何表达递归方面略有不同。请参阅 pcrepattern 联机帮助页中的“递归模式”和“与 Perl 的递归差异”部分。例如:Perl 可以处理 ^(.|(.)(?1)\2)$
其中 PCRE 需要 ^((.)(?1)\2|.)$
相反。
对递归模式的需求出人意料地频繁出现。一个常见的例子是当您需要匹配可以嵌套的内容时,例如平衡括号、引号,甚至 HTML/XML 标记。这是平衡括号的匹配:
\((?:[^()]*+|(?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。问题是这只是一场比赛,而不是一场捕获。而且您真的不想只用捕获括号包围整个事物,因为这并不能告诉您哪个作品与哪个部分相匹配。使用前面提到的 Regexp::Grammars 模块,我们可以。
#!/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
}
}
如您所见,通过在模式中使用稍有不同的表示法,您现在可以在 %/
中为您存储整个解析树。变量,所有东西都被整齐地标记。转换的结果仍然是一个模式,如 =~
所示。运算符(operator)。这有点神奇。
关于regex - "modern"正则表达式的识别能力,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4840988/
我想使用 Extjs 6.5.2 尝试 hello world 示例。当我尝试运行以下代码时 var containerPanel = Ext.create('Ext.panel.Panel'
在听说了Perl生态系统的新组成部分(例如Moose,DeclareX和Catalyst)之后,我认为对Perl感到高兴。不幸的是,我可以找到所有针对Perl 5.8或5.6的入门资料,而对这些较新的
HList package是基于现在古老的 Haskell 技术。一个简单的问题是:考虑到过去 8 年 Haskell/GHC 开发的所有精彩新特性,“现代”HList 的构建方式会非常不同吗?我意识
真正的现代正则表达式实际上可以识别什么类型的语言? 只要存在带有反向引用的无限长度捕获组(例如 (.*)_\1),正则表达式现在就会匹配非常规语言。但这本身不足以匹配 S::= '(' S ')' |
我必须使用 modernizer 来检测浏览器是否支持“cssscrollbar”属性,true 或 false。基于这个值,我必须做一些事情,比如添加插件和 CSS。 我正在使用下面这样的东西,我不
如何在 Relay Modern 中取消订阅? 我已经按照 How to GraphQL React + Relay 上的订阅教程进行操作但它没有提及您如何取消订阅,也没有提及 Relay Moder
我听说过很多关于这个“现代 Perl”的事情。它是什么? 我听到的一件事是新的开放语法: open my $FH, '<', $filename 并不是 open FH, "<$filename";
{这是现代接力赛} 在我的 UserQuery.js 中, class UserQuery extends Component { render () { return (
类(class)TypeCast可以追溯到 2004 年,因此 Haskell 相当“古老”(尽管仍然相当出色)。我的问题是:如果今天在最先进的 GHC 中重新实现 [最好是 7.6,但是继续,使用
我的 React 项目中有以下设置: export default class OverviewScreen extends React.Component { public render() {
在问这个可能含糊不清的问题之前,我搜索了 SO,发现许多对“现代浏览器”的引用,但没有定义。由于这是一个被广泛使用和引用的术语,令我惊讶的是我在 Internet 上找不到定义甚至描述。 那么,在 2
我正在使用字典来使用登录页面中的用户详细信息来填充列表内容。 但是我需要为每个列表项创建一个单独的源页面。 在页面加载静态源页面的那一刻,我是否可以动态设置它,即每个创建的列表链接的源页面? 或者,如
我正在 Visual Studio 上(在 C# WPF 应用程序模式下)重新制作一个在 AutoPlay media Studio 上制作的应用程序。 当我需要从计算机中获取文件时,我在 Stack
我有与此类似的 C++ 类: class A{ std::string str; public: A(std::string &str) : str(str){} int cm
现代浏览器(即 Firefox 3+、Safari 4+、IE 7+)中正则表达式的最大大小是多少?假设一个简单的正则表达式,例如“foo|bar|baz|woot|...” 最佳答案 您可以使用此代
我已经安装了 R 包 extrafont和 fontcm .然后尝试在 Sweave 中使用 Computer Modern 字体绘制数据: >= plot(na, family="CM Roman"
有什么方法可以找出现代用户界面的当前主题颜色集吗? WinAPI 函数或注册表值对我来说可能是最好的解决方案。 我的意思是当前主题颜色 this . 最佳答案 在UxTheme.dll 中有一个名为G
我正在使用带有现代中继的 react native 应用程序。 目前我们的应用程序的 fetchQuery 实现,只是在网络上做一个 fetch (就像在 https://facebook.githu
我正在使用基于 token 的身份验证,并且想知道如何在 Relay Modern 中将其完全结合在一起。我已经完成一半了。任何帮助深表感谢。这是我的设置: 位于内部顶层我渲染入口点。 内部我有一个在
是否可以使valijson与Nlohmann的json解析器一起使用,以从文件中引用其他文件中的子模式来读取架构? json mySchemaDoc; if (!valijson::utils::lo
我是一名优秀的程序员,十分优秀!