在正则表达式内赋值
— 焉知非鱼assignment within regex
Richard 想…
提供一种简单的方法来命名和从 regex 中挑选信息,而不必计算括号。
我可以毫不犹豫地说,Raku(以及在其改名之前的Perl 6)已经实现了这个目标-但所有的细节都与提议的不同。
原因有二。
首先,Richard 假设了 Perl 5 的 regex 语法的一个相当直接的扩展,他提出的语法,(?$hours=..)
的命名捕捉是有意义的。相反,Raku regex 语法是一个相当新的东西,所有非字母数字字符都是潜在的元字符,因此要么被使用,要么为某一目的保留。这使得比 (?$name=regex)
更容易的语法可用于命名捕捉。
第二种情况更为深刻。Raku 的设计者们意识到,只有当重用从头开始时,regex 才能真正强大起来。而实现这一点的最好方法就是让 regex 成为一等公民。
我想在这一点上多说几句:考虑一下函数(和闭包)作为现代编程语言中一等公民的力量。Lisp 已经向我们展示了你可以用它们做什么,现在基本上每个编程语言都得到了它们。像 Perl、Ruby、Javascript 和 Python 这样的动态语言是相当早的适配者,像 C#
和 F#
这样的现代静态类型语言也得到了它们;甚至 Java 最终也赶上了。Java 甚至没有函数,只有方法,而现在它有了闭包,你可以到处传递。
依我的愚见,将 regex 提高到一级公民的水平,并引入简洁的调用语法,给 regex 带来了类似的提升。
在以前,人们的常识是不能用 regex 来解析 XML(或其他任意嵌套的语言),因为它们不是计算机科学意义上的常规语言。Perl 5 对此有一些变通方法,但它们太笨拙和啰嗦了,我甚至没有看到它们被多次推荐,我的一般印象是,如果你使用它们,只是因为缺乏好的替代品。
在 Raku 中就不一样了:regex 中的 <subrule>
会调用另一个叫做 subrule
的 regex,所以你就有了递归(以及与 RFC 112 的讨论相关的,命名捕获)。这种递归使 regex 从常规语言进入 Chomsky Hierarchy 中的无上下文语言领域。但比起递归,命名的 regex 更允许更容易的重用、隔离测试以及其他所有一类公民赋予函数的美妙东西。它也让人们对用 regex 解析 XML 和其他语言的感情从 “你是认真的吗”? 变成了 “当然,这是最好的工具”。
调用语法 <subrule>
意味着一个命名捕获,事实证明,这已经很方便了,在现实世界的解析器中,显式的命名捕获(不与调用绑定)其实是非常罕见的。不过一个显式的语法是存在的,它就是 $<capturename>=[...]
。
这就带来了第二个有趣的地方。RFC 112 并不只是谈论命名捕获,而是暗示它们被直接存储到同名的变量中。
这是有问题的,原因有很多。
-
作用域。regex 可以在程序的两个非常不同的部分被声明和使用。强制变量在作用域内,会使捕获语法成为一个作用域不必要的大的源变量(我敢说是全局的?),这是一个明显的反模式。
-
量词。在 RFC 211 语法中,像
(?$char=.)+
这样匹配字符串 abc 的 regex 会发生什么?$char
里有什么?sigil 意味着一个标量,所以… 也许是最后捕获的c
?然后扔掉所有其他的匹配?听起来不是很好。或者(?@char=.)
会有一个包含所有捕获的数组,但这样一来,当写一个 regex 时,你必须知道是否有人后来想在一个量词内使用它。也不是很好。 -
组合。将匹配项绑定到一个变量上,假设 regex 是作为一个顶层结构使用的,而不是更大事情的一部分。
-
递归。我还需要详细说明吗?可能不需要。
现在在 Raku 中实现的解决方案更适合于一类公民 regex 的世界:对于每个 regex 匹配都有一个 Match 对象。顶级匹配对象存储在变量 $/
中,所以访问一个命名捕获键是 $/<key>
,甚至还有一个简写,$<key>
。只是比最初提出的 $key
长了两个字符。
不过这个解决方案在使用在组合的情况下就会大放异彩,比如说。由于命名捕获对应于一个 regex 匹配,它也是一个 Match 对象,所以我们得出一棵匹配树(都是一样的)。或者改写为:一个 regex 匹配已经是一棵语法树。
我认为这个 RFC 是一个很好的例子,它发现了一个真正的痛点和问题,并提出了一个解决方案。这个解决方案的某些方面在语言设计过程中得以幸存,但大部分细节没有,因为语言的变化远不止于它勉强是 Perl 5 加上通过 RFC 的一些扩展。
我从2007年左右开始参与 Perl 6 项目,看着其中的一些转变;对于 regex,大部分的整合和重新设计工作已经完成。我看着这些实现变得更加强大,甚至到处帮了一点小忙。
生活在这个过程中是一种神奇的体验,就像现在的结果一样神奇。