gpt4 book ai didi

regex - perl6语法,不确定示例中的某些语法

转载 作者:行者123 更新时间:2023-12-03 14:54:57 25 4
gpt4 key购买 nike

我仍在学习perl6,并且正在阅读此页面上的语法示例:http://examples.perl6.org/categories/parsers/SimpleStrings.html;我已多次阅读有关正则表达式的文档,但仍有一些我不理解的语法。

token string { <quote> {} <quotebody($<quote>)> $<quote> }


问题1:令牌中的“ {}”在做什么?捕获标记为<()>,嵌套结构为tilda'('〜')';但是{}是什么?

token quotebody($quote) { ( <escaped($quote)> | <!before $quote> . )* }


问题2a:<>中的转义($ quote)将是一个正则表达式函数,对吗?它以$ quote作为参数并返回另一个正则表达式?

问题2b:如果我想表示“不在报价前的字符”,我应该使用“。<!before $ quote>”而不是“ <!before $ quote>”。 ??

token escaped($quote) { '\\' ( $quote | '\\' ) } # I think this is a function;

最佳答案

TL; DR @briandfoy已提供an easy to digest answer。但是这里有他没有提到的巨龙。还有漂亮的蝴蝶。这个答案很深。


问题1:令牌中的{}在做什么?


这是一个代码块1,2,3,4。

它是一个空值,仅用于强制$<quote>中的quotebody($<quote>)在正则表达式开始时求值为<quote>捕获的值。

$<quote>在不插入代码块的情况下不包含正确值的原因是Rakudo Perl 6编译器限制或与“匹配变量的发布”有关的错误。

Rakudo对匹配变量进行“公开”

莫里茨·伦茨(Moritz Lenz)在a Rakudo bug report中指出:“除非有必要,否则正则表达式引擎不会发布匹配变量”。

他用“ regex引擎”表示NQP中的regex /语法引擎,它是Rakudo Perl 6编译器的一部分。3

他用“匹配变量”表示存储匹配结果捕获的变量:


当前匹配变量$/;
编号的子匹配变量$0$1等;
形式为$<foo>的命名子匹配变量。


通过“发布”,他表示正则表达式/语法引擎会执行所需的操作,以便对正则表达式中的任何变量(令牌也为正则表达式)的任何提及都将评估为它们应该具有的值拥有他们。在给定的正则表达式中,匹配变量应该包含一个Match object,对应于在处理该正则表达式的任何给定阶段为其捕获的内容,如果没有任何内容,则为Nil

“被认为是必需的”他表示正则表达式/语法引擎对匹配过程中的每个步骤之后是否值得进行发布工作进行了保守的呼吁。 “保守”是指引擎通常避免发布,因为它会使事情变慢并且通常是不必要的。不幸的是,有时对于实际何时需要发布过于乐观。因此,程序员有时需要通过显式插入代码块来干预,以强制发布匹配变量(以及其他变量的其他技术5)。正则表达式/语法引擎有可能随着时间的推移在这方面有所改进,从而减少了需要人工干预的情况。如果您希望帮助实现这一点,请创建对您而言与现有相关bug有关的测试用例。5

$<quote>值的“发布”

此处命名的捕获$<quote>就是这种情况。

据我所知,所有子匹配变量在没有周围构造的情况下直接写入正则表达式时都正确地引用了它们的捕获值。这有效:

my regex quote { <['"]> }
say so '"aa"' ~~ / <quote> aa $<quote> /; # True


我认为6 $<quote>获得正确的值,因为它被解析为regex lang语构造。4

相反,如果 {}

token string { <quote> {} <quotebody($<quote>)> $<quote> }


那么 $<quote>中的 quotebody($<quote>)将不包含开头 <quote>捕获的值。

我认为这是因为 $<quote>在这种情况下被解析为主要的lang语构造。


问题2a: escaped($quote)中的 <>是正则表达式函数,对吗?它以 $quote作为参数


这是一个很好的第一近似值。

更具体地说,形式为 <foo(...)>的正则表达式原子是方法 foo的调用。

所有正则表达式-无论是以 tokenregexrule/.../或任何其他形式声明的-都是方法。但是用 method声明的方法不是正则表达式:

say Method ~~ Regex; # False
say WHAT token { . } # (Regex)
say Regex ~~ Method; # True
say / . / ~~ Method; # True


当遇到 <escaped($quote)>正则表达式原子时,正则表达式/语法引擎既不知道也不关心 escaped是否为正则表达式,也不了解 the details of method dispatch inside a regex or grammar。它只是调用方法分派,将调用者设置为由正则表达式构造的 Match对象。

该调用将控制权最终运行该方法。事实证明,正则表达式/语法引擎只是递归地回调自身,因为通常是一个正则表达式调用另一个正则表达式的问题。但这不一定。


并返回另一个正则表达式


不,形式为 <escaped($quote)>的正则表达式原子不会返回另一个正则表达式。

相反,它调用将/应该返回 Match对象的方法。

如果调用的方法是正则表达式,则P6将确保该正则表达式自动生成并填充 Match对象。

如果调用的方法不是正则表达式,而是普通方法,则该方法的代码应已手动创建并返回了 Match对象。莫里茨在他对SO问题 Can I change the Perl 6 slang inside a method?的回答中展示了一个例子。

Match对象返回到“正则表达式/语法引擎”,该引擎驱动正则表达式匹配/语法解析。3

然后,引擎根据结果决定下一步该做什么:


如果匹配成功,则引擎将更新与调用正则表达式相对应的总体匹配对象。更新可以包括将返回的 Match对象保存为调用正则表达式的子匹配捕获。这就是构建匹配/解析树的方式。
如果匹配失败,则引擎可能会回溯,撤消之前的更新;因此,随着匹配的进行,解析树可能会动态增长和收缩。



问题2b:如果我想表示“不在报价前的字符”,是否应该使用 . <!before $quote>而不是 <!before $quote> .


是。

但这不是 quotebody正则表达式所需要的,如果这就是您要说的。

在谈到后一个主题时,在@briandfoy的答案中,他建议使用“匹配...任何非引号的内容”构造,而不要进行否定的前瞻( <!before $quote>)。他的观点是,与“不是引号”相匹配比“不是在引号之前?然后匹配任何字符”更容易理解。

但是,如果引号是一个变量,其值设置为捕获引号,则绝不是直截了当的。这种复杂性是由于Rakudo中的错误所致。我已经解决了我认为最简单的方法,但认为最好还是坚持使用 <!before $quote> .,除非/直到修复了这些长期存在的Rakudo错误为止。5


token escaped($quote) { '\\' ( $quote | '\\' ) } # I think this is a function;


这是一个令牌,它是一个 Regex,它是一个 Method,它是一个 Routine

say token { . } ~~ Regex;   # True
say Regex ~~ Method; # True
say Method ~~ Routine; # True


正则表达式主体中的代码( { ... }位)(在这种情况下,该代码是 .中的唯一 token { . },它是与单个字符匹配的正则表达式原子),写在P6 regex中。 cc语”,而 method例程主体内部使用的代码则写在主P6“ s语”中。4

使用 ~

regex tilde (~) operator是专门为该问题所涉及的示例中的解析而设计的。它读起来更好,因为它可以立即识别,并且可以将开始和结束的报价保持在一起。更重要的是,它可以在发生故障时提供人为可理解的错误消息,因为它可以说出所要查找的结束定界符。

但是,如果您在正则表达式 ~运算符旁边(正反两面)插入一个正则表达式(其中有或没有代码),则必须考虑一个关键问题。除非您特别希望波浪号将代码块视为其自己的原子,否则您将需要对代码块进行分组。例如:

token foo { <quote> ~ $<quote> {} <quotebody($<quote>) }


将匹配一对 <quote>,而它们之间没有任何匹配。 (然后尝试匹配 <quotebody...>。)

相反,这是一种在 string语法中复制 String::Simple::Grammar令牌的匹配行为的方法:

token string { <quote> ~ $<quote> [ {} <quotebody($<quote>) ] }


脚注

1 2002年,拉里·沃尔(Larry Wall)撰写了 "It needs to be just as easy for a regex to call Perl code as it is for Perl code to call a regex."。计算机科学家指出,您不能在 a traditional regular expression中间使用过程代码。但是很久以前,Perls导致了向 non-traditional regexes的转换,而P6得出了合理的结论-简单的 {...}就是在正则表达式中间插入任意过程代码所需要的全部。语言设计和regex /语法引擎实现3确保可以识别正则表达式中的传统风格纯声明性区域,因此可以将正式的正则表达式理论和优化应用于它们,但是仍然可以插入任意的正则程序代码。简单用法包括 matching logicdebugging。但是天空是极限。

2正则表达式的第一个过程元素(如果有的话)终止正则表达式的“声明性前缀”。插入空代码块( {})的常见原因是,当为正则表达式中的给定 longest alternation提供所需的匹配语义时,故意终止正则表达式的声明性前缀。 (但这不是将其包含在您想要了解的令牌中的原因。)

3松散地说, NQP中的正则表达式/语法引擎对P6而言是 PCRE对P5而言。

关键区别在于,正则表达式语言及其关联的正则表达式/语法引擎以及与之合作的主要语言(在Rakudo情况下为Perl 6)在控制方面是同等的。这是 Larry Wall's original 2002 vision for integration between regexes and "rich languages"的实现。每种语言/运行时都可以相互调用,并通过高级FFI进行通信。因此,它们可以看起来像,可以充当,甚至可以充当,具有协作语言和协作运行时的单个系统。

(P6设计使得可以通过两个互补的P6 FFIs:元模型FFI 6model和/或C调用约定FFI,对所有语言进行显式设计或改装,以便以“丰富”的方式进行协作。 NativeCall。)

4 P6语言实际上是一起使用的子语言(也称为语)的集合。当您读取或编写P6代码时,您正在读取或编写源代码,该源代码以一种语开始,但部分内容以其他语编写。文件的第一行使用主语。可以说这类似于英语。正则表达式用另一种语编写;假设这就像西班牙语。因此,对于 the grammar String::Simple::Grammar,代码以英语( use v6;语句)开头,然后递归为西班牙语(在 {rule TOP {之后),即 ^ <string> $位,然后返回译成英文(注释以 # Note ...开头)。然后,将其递归为 <quote> {} <quotebody($<quote>)> $<quote>的西班牙语,并在该西班牙语的中间,在 {}代码块处,再次递归为另一级英语。这就是西班牙文中的英文。当然,代码块是空的,所以就像用英语写/读任何东西,然后立即放回西班牙语一样,但重要的是要了解,这种递归的语言/运行时堆栈是P6的工作方式,两者都是一个单一的总体语言/运行时,以及与其他非P6语言/运行时的配合。

5在应用两个潜在的改进过程中,我遇到了一些错误,这些错误已在本脚注的末尾列出。 (在briandfoy的答案和本答案中都提到了。)两个“改进”是使用 ~构造,而使用“非引号”构造而不是使用 <!before foo> .。最终结果,再加上相关的错误:

grammar String::Simple::Grammar {
rule TOP {^ <string> $}
token string {
:my $*not-quote;
<quote> ~ $<quote>
[
{ $*not-quote = "<-[$<quote>]>" }
<quotebody($<quote>)>
]
}
token quote { '"' | "'" }
token quotebody($quote) { ( <escaped($quote)> | <$*not-quote> )* }
token escaped($quote) { '\\' ( $quote | '\\' ) }
}


如果有人知道更简单的方法,我很乐意在下面的评论中听到。

我最终在RT bug数据库中搜索了所有正则表达式错误。我知道不是错误数据库,但是我认为注意以下几点是合理的。爱ui的前两个问题直接与发布匹配变量有关。


< > regex调用语法仅在使用它的regex的父范围内查找词法,而不在regex本身的范围内查找。” rt #127872
Backtracking woes as they relate to passing arguments in regex calls
看起来有很多讨厌的线程错误。多数归结为一个事实,即多个正则表达式功能在后台使用 EVAL并且 EVAL尚不是线程安全的。幸运的是,官方文档提到了这些。
Can't do recursive grammars due to .parse setting $/


6这个问题和我的回答将我推向了对P6雄心勃勃和复杂方面的理解的外部界限。我计划很快对nqp和完整P6之间的精确交互以及它们的regex lang语和主要between语之间的移交有更深入的了解,如上面的脚注中所述。 (我的希望目前主要取决于刚购买 commaide。)如果/有一些结果,我将更新此答案。

关于regex - perl6语法,不确定示例中的某些语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51408141/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com