“现代”正则表达式的识别能力

2024-01-16

真正的现代正则表达式实际上可以识别哪一类语言?

每当存在带有反向引用的无限长度捕获组时(例如(.*)_\1) 正则表达式现在匹配非常规语言。但这本身并不足以匹配类似的东西S ::= '(' S ')' | ε— 匹配括号对的上下文无关语言。

递归正则表达式(这对我来说是新的,但我确信 Perl 和 PCRE 中存在)似乎至少可以识别大多数 CFL。

有人做过或读过这方面的研究吗?这些“现代”正则表达式有哪些限制?它们对 LL 或 LR 语法的识别严格程度比 CFG 严格多还是严格少?或者是否存在两种语言可以被正则表达式识别但不能被 CFG 识别and相反?

相关论文的链接将不胜感激。


模式递归

通过递归模式,您可以得到一种递归下降的形式matching.

这对于各种问题来说都很好,但是一旦你想真正进行递归下降parsing,您需要到处插入捕获组,并且以这种方式恢复完整的解析结构很尴尬。达米安康威的正则表达式::语法 http://search.cpan.org/~dconway/Regexp-Grammars-1.012/lib/Regexp/Grammars.pmPerl 的模块将简单模式转换为等效模式,自动将所有命名捕获转换为递归数据结构,从而更轻松地检索已解析的结构。我在本文末尾有一个比较这两种方法的示例。

递归的限制

问题是递归模式可以匹配什么类型的语法。嗯,他们当然是递归下降 http://en.wikipedia.org/wiki/Recursive_descent_parser类型匹配器。我唯一想到的是递归模式无法处理左递归 http://en.wikipedia.org/wiki/Left_recursion.这对您可以应用它们的语法类型施加了限制。有时您可以重新排序您的产品以消除左递归。

顺便说一句,PCRE 和 Perl 在如何表达递归方面略有不同。请参阅“递归模式”和“与 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 递归工作方式受到限制。

正确的解析

对我来说,上面的例子大多是玩具比赛,而不是全部that有趣,真的。当你有一个真正的语法并试图解析时,它就会变得有趣。例如,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。问题是这只是一场比赛,而不是一场捕获。而且您真的不想只用捕获括号包围整个事物,因为这并不能告诉您哪个作品与哪个部分相匹配。使用前面提到的 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
    }
}

正如您所看到的,通过在模式中使用稍有不同的表示法,您现在可以得到将整个解析树存储在%/变量,所有东西都被整齐地标记。转换的结果仍然是一个模式,正如您可以看到的=~操作员。这有点神奇。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

“现代”正则表达式的识别能力 的相关文章

  • 正则表达式,选择最接近的匹配

    假设以下单词序列 BLA text text text text text text BLA text text text text LOOK text text text BLA text text BLA 我想做的是将 BLA 中的文本
  • 如何在 perl 中合并两个数组,交替每个数组中的值

    假设我有 2 个如下所示的数组 a1 Vinay Raj harry b1 dude rock 合并后我想要这样的结果 Vinay dude Vinay rock Raj dude Raj rock harry dude harry roc
  • 我怎样才能挂钩 Perl 的 use/require 以便抛出异常?

    如果文件已经加载 是否可以挂载到use require所以我可以抛出异常 在我即将到来的nextgen blacklist http github com EvanCarroll nextgen blob blacklist lib nex
  • 如何在Matlab中打印带有千位分隔符的整数?

    我想使用逗号作为千位分隔符将数字转换为字符串 就像是 x 120501231 21 str sprintf 0 0f x 但随着效果 str 120 501 231 21 如果内置fprintf sprintf做不到 我想可以使用正则表达式
  • Java 正则表达式中的逻辑 AND

    是否可以在 Java Regex 中实现逻辑 AND 如果答案是肯定的 那么如何实现呢 正则表达式中的逻辑 AND 由一系列堆叠的先行断言组成 例如 foo bar glarch 将匹配包含所有三个 foo bar 和 glarch 的任何
  • 由于重复捕获组而不是捕获重复组,正则表达式不匹配

    我有以下正则表达式 A G A G 具有以下表达式 A BsCb 我期望 3 个匹配结果 A Bs Cb 但测试在https regex101 com https regex101 com 只给我最后一场比赛Cb 并告诉我重复捕获组只会捕获
  • bash 支持字边界正则表达式吗?

    我试图在再次添加该单词之前匹配列表中是否存在该单词 以避免重复 我正在使用 bash 4 2 24 并尝试以下操作 foo bmyword b also foo
  • [Regex]::Replace() 和 -replace 有什么区别?

    我明白了之间的区别 Replace and replace 但是什么是 replace and Regex Replace 我测试了以下两个代码 但对我来说结果完全相同 我还提到了 PowerShell Cookbook O reilly
  • 删除匹配前的一个单词和一个单词

    匹配之前的一个单词可以是一组任何符号 例如 D E F 我有一个正则表达式 s w s XXX 输入示例 This is KKK M D D xXx PPP输出示例 This is KKK PPP 所以我需要删除 XXX 之前的 1 个单词
  • 为正则表达式编写解析器

    即使经过多年的编程 我很羞愧地说我从未真正完全掌握正则表达式 一般来说 当问题需要正则表达式时 我通常可以 在一堆引用语法之后 想出一个合适的正则表达式 但我发现自己越来越频繁地使用这种技术 所以 自学并理解正则表达式properly 我决
  • 如何将会话管理添加到简单的 Perl CGI 网页?

    我有一个简单的网页 到目前为止不需要任何登录 它是用 Perl CGI 编程的 我想知道添加会话支持以便获得登录信息的步骤 我不需要非常复杂的方法 因为网页非常简单 另外 我想要一些关于支持 Perl 会话所需的技术 库的建议 我在很多很多
  • 什么是仅匹配空字符串的正则表达式?

    有很多关于正则表达式的帖子来匹配潜在地空字符串 但我找不到任何提供正则表达式的字符串only匹配一个空字符串 我知道 将匹配任何行的开头并且 将匹配任何行的结尾以及字符串的结尾 像这样 匹配的内容远不止空字符串 如 n foobar n n
  • 在 qx 运算符中将 perl 数组拆分为单独的参数

    我试图将一组参数传递给qx操作员 考虑 my files qw A txt B txt print qx ls files 这给出了错误 ls cannot access A txt B txt No such file or direct
  • 使用 -T 开关运行时 $ENV{ENV} 不安全

    当我尝试最后一个例子时perlfaq5 如何计算文件中的行数 http perldoc perl org perlfaq5 html How do I count the number of lines in a file 我收到一条错误消
  • git 匹配多个单词的标签

    我们可以得到最后一个 git 标签 它以一个单词 例如 TEST 开头 如下所示 git describe tag dirty match TEST 我想知道如何获得最后一个以 word1 开头的标签orword2 例如测试OR跑步 我尝试
  • ruby 正则表达式匹配模式的多次出现

    我正在寻找构建一个 ruby 正则表达式来匹配模式的多次出现并将它们返回到数组中 模式很简单 即 两个左括号 一个或多个字符 后跟两个右括号 这就是我所做的 str Some random text lead first name and
  • 在 Perl 中使用数据引用的正确方法

    我有一组想要处理的数据 为了简化我的代码 最好通过指向原始数据的引用数组来访问我的数据的某些子集 比解释更好的是 我写下了这个例子 它还没有工作 最后 我想更新原始数据 而不必更新所有子集 用 Perl 可以做这样的事情吗 usr bin
  • 如何在附加的 sqlite 数据库中创建外键?

    我正在尝试创建一个 sqlite3 数据库作为模拟生产环境的测试环境 由于生产的设置方式 表处于多个模式中 我已经在 DBIx Class 中设置了类 使用 schema gt storage gt dbh do将数据库与架构附加在一起 并
  • Perl:测试输入阅读器?

    有没有一种方法可以使用标准 Test 等模块自动测试 Perl 程序是否正在读取输入 例如标准输入正确吗 例如 测试一个从 STDIN 读取两个整数并打印它们之和的程序 这不是 100 清楚你的意思 我会回答假设你想编写一个测试脚本来测试你
  • Perl 正则表达式图灵完备吗?

    我见过 Ruby 和 Perl 程序员做了一些事情复杂的代码挑战 https codegolf stackexchange com questions 3596 regex validating regex完全用正则表达式 这前瞻和后瞻 h

随机推荐

  • 替换 AuthenticationHandler 进行集成测试

    我有一个 web 应用程序 它使用浏览器客户端的表单身份验证以及对 odata 源的 api 访问的基本身份验证 这在生产中有效 但现在我正在努力使其可测试 我使用 WebApplicationFactory 方法 还成功实现了测试身份验证
  • vue中如何调整图片大小

    我将图像从nodejs上传到vue 并将图像放入v卡中 但图像被截断了 如何在不剪切的情况下调整图像大小 在 v img 中使用 包含 属性
  • android:我想在 WebViewb 中使用我的自定义字体

    我想在 WebViewb 中使用我的自定义字体我的 html 文件已加载到 webView 中 但仍然没有字体我的字体有 Unicode 字符我在 android 2 2 上工作 mWebView loadUrl file android
  • Laravel Blade 模板在尝试获取非对象的属性时如何返回 null 而不是 ErrorException

    我正在编写一些 Laravel Blade 模板 并且我的模型可能包含空对象 我非常想尝试获取对象属性 如果出现错误 则返回 null 所以不必这样写 if model gt child object that may be null mo
  • 如何链接相同或不同文件夹中的html页面?

    如果 html 页面位于相同或不同的文件夹中 而无需编写完整路径 如何链接到它们 在同一文件夹中 只需使用文件名 a href thefile html my link a 在父文件夹的目录中 a href thefile html my
  • python 中的迭代

    您好 我想创建一些代码来打印一个如下所示的框 代码应该使用循环来打印一行框 使用 for i in range 5 不应该使用 IF 语句来解决这个问题 只使用一个框 如下所示 我尝试使用下面的代码 但没有产生所需的输出 请帮忙 for i
  • Firebase:自动创建/更新多个子节点

    假设我有一个带有 用户 节点和 宠物 节点的项目 当用户获得宠物时 我想将宠物的密钥添加到用户的 pets 节点 并将用户 ID 添加到宠物的 owner 节点 Example users user1 pets pet1 true pet3
  • 在 Xcode 11 中将分支合并到 master 中?

    我一定在这里遗漏了一些非常简单的东西 在早期版本的 Xcode 上 我从未遇到过将分支合并到 master 中的问题 但在使用 Xcode 11 时 我在任何项目上都没有该选项 我应该如何合并到master 谢谢 这是一个令人沮丧的 Xco
  • 使用 C# 从 Parquet 文件中读取前 100 行

    我有这些巨大的镶木地板文件 存储在一个 blob 中 有超过 60 万行 我想检索前 100 个 以便我可以将它们发送到我的客户端应用程序 这是我现在用于此功能的代码 private async Task lt Table gt getPa
  • 如何查找 Ruby 哈希的“nil”值并将其替换为“None”或 0?

    我试图深入到数组嵌套哈希迭代中的每个值并替换所有值nil值带有 无 或 0 之类的值 请参阅我的代码 它显然不起作用 在将其传递到 Rails 中的视图进行迭代和渲染之前 我需要修复此问题 我的控制器 def show results Re
  • SECURITY_ERR:调用 Canvas 的 toDataURL 方法时出现 DOM 异常 18

    当我尝试从在 Internet Explorer 和 Safari 浏览器上绘制 SVG 图像的画布检索数据 URL 时 出现以下错误 而其他浏览器都正常工作 此外 SVG 图像还包含一些
  • 使用sequelize的种子数据的不同目录

    我希望在开发和生产之间有不同的种子数据 我如何在配置中指定它 我知道在 sequelizerc我可以加载动态配置文件并指定seeders path sequelizerc const path require path module exp
  • C 中的库存程序。需要有关如何从库存中删除项目的帮助

    这是一个保存库存的程序 该程序显示一个选项菜单 除了删除条目功能之外 其他一切都很完美 我不知道如何让它删除一个功能 我放置了一个变量来查找位置 但我真的不知道如何 我输入要删除的项目名称 然后输入显示条目 它会陷入无限混乱 有人帮助我如何
  • 使用 torchtext 时出现 ImportError

    当我尝试运行这行代码时 出现以下错误 from torchtext data import Field TabularDataset BucketIterator Iterator ImportError cannot import nam
  • Gradle从哪个版本开始支持Java 17

    当尝试配置项目时 我收到错误 不支持 Java 您的构建当前配置为使用 Java 17 0 1 和 Gradle 7 0 不幸的是 没有信息官方文档 https docs gradle org current userguide compa
  • CAtlList::RemoveAt 是否会使现有的 POSITIONS 无效?

    我正在看这个 其中 m Rows 是 CAtlList void CData RemoveAll size t cItems m Rows GetCount POSITION Pos m Rows GetHeadPosition while
  • 如何按特定顺序自动启动程序?

    我的 i3 配置文件中有以下几行 Startup applications exec firefox exec gnome terminal exec nautilus 这些行按预期启动 firefox gnome terminal 和 n
  • Erlang 和带有西里尔字母的二进制

    我需要能够使用其中包含西里尔字符的二进制文件 我尝试只写 lt lt gt gt 但我收到了 badarg 错误 如何在 Erlang 中使用西里尔字母 或 unicode 字符串 如果你想输入上面的表达式erlang shell 请阅读u
  • 使用基于单选按钮值的 javascript(Node JS) 将数据插入 mysql(Sequelize)

    我有下面的 json 对象 phoneno field1 Mohamed field2 123456789 field3 Sameer field1 Ganesh field2 987654321 field3 Pandiyan sende
  • “现代”正则表达式的识别能力

    真正的现代正则表达式实际上可以识别哪一类语言 每当存在带有反向引用的无限长度捕获组时 例如 1 正则表达式现在匹配非常规语言 但这本身并不足以匹配类似的东西S S 匹配括号对的上下文无关语言 递归正则表达式 这对我来说是新的 但我确信 Pe