Regex/token/rule 来匹配嵌套的大括号?
Regex/token/rule to match nested curly braces?
我需要匹配 BibTeX 文件中 key = value
对的值,它可以包含任意嵌套的大括号,由大括号分隔。我最多只能匹配两个深嵌套花括号,比如 {some {stuff} like {this}}
和 kludgey:
token brace-value {
'{' <-[{}]>* ['{' <-[}]>* '}' <-[{}]>* ]* '}'
}
我对再往下一层的想法感到不寒而栗......但是正确解析我的 BibTeX 内容至少需要三层深度。
是的,我知道周围有 BibTeX 解析器,但我需要获取完整的条目以进行进一步处理,同时还要查看几个键。我的 *.bib
文件相当乏味(我不介意手动处理一些零散的条目),问题是我有很多文件,而且有很多重叠。但是一些“相同”的条目有不同的键或额外的数据。我想将它们合并成几个主文件(BibTeX 背后的整个想法,对吧?)。如果 bibtool
给出一个大约 20,000 行没有重复(哈!)的文件...
在仔细阅读 Lenz 的“使用 Perl 6 正则表达式和语法进行解析”(Apress,2017 年)之后,我意识到“正则表达式”机制(基于回溯)实际上可能比官方承认的更强大,因为正则表达式可以调用另一个,我没有看到任何地方禁止 递归 调用。
在深入研究之前,了解一些上下文无关语法:描述嵌套大括号(仅此而已)的一种方法是使用语法:
S -> { S } S | <无>
即,嵌套大括号是左大括号、嵌套大括号、右大括号、更多嵌套大括号;或者什么都没有。这或多或少直接翻译成 Raku(没有空的正则表达式,通过使构造可选来伪造它):
my regex nb {
[ '{' <nb> '}' <nb> ]?
}
瞧,这行得通。需要修复以避免捕获,终止回溯(如果第一次尝试不匹配,它永远不会匹配),并用“其他任何东西”填充物装饰。
my regex nested-braces {
:ratchet
<-[{}]>*
[ '{' <.nested-braces> '}' <.nested-braces> ]?
<-[{}]>*
};
这与我的测试用例一致。
对于不太喜欢冒险的人,Perl 有 Text::Balanced
模块(以前称为 Perl 5,可使用 Inline::Perl5
从 Raku 调用)。不幸的是,在语法中对我没有直接用处。
解决方案
A way to describe nested braces (and nothing else)
假定一个名为 &R
的规则,如果我正在编写一个快速的小型一次性脚本,我可能会编写以下模式:
\{ <&R>* \}
如果我正在编写一个应该可维护的更大的程序,我可能会编写一个语法,并且使用名为 R
的规则,模式将是:
'{' ~ '}' <R>*
后者避免了leaning toothpick syndrome and uses the regex ~
operator.
这些都将解析任意深度嵌套的成对大括号,例如:
say '{{{{}}}}' ~~ token { \{ <&?ROUTINE>* \} } # 「{{{{}}}}」
(&?ROUTINE
指的是它出现的例程。正则表达式是例程。(虽然你不能在用 / ... /
语法声明的正则表达式中使用 <&?ROUTINE>
。 )
regex
对比 token
kill backtracking
my regex nested-braces {
:ratchet
用 regex
和 token
声明的模式之间的唯一区别是前者将棘轮 关闭 。所以使用它然后立即转动棘轮 on 是非常不合常理的。相反:
my token nested-braces {
回溯
the "regex" machinery (based on backtracking)
grammar/regex 引擎 包括 回溯作为一项 可选 功能,因为这有时正是人们想要的。
但是引擎不是“基于回溯”,许多grammars/parsers很少或根本不使用回溯。
递归
a regex can call another, and nowhere do I see a prohibition on recursive calls.
仅此一项对于现代正则表达式引擎来说并没有什么特别之处。
PCRE 自 2000 年起支持递归,自 2003 年起命名正则表达式。Perl 的默认正则表达式引擎自 2007 年起支持两者。
随着时间的推移,他们对更深层次的递归和更多命名的正则表达式的支持一直在增加。
Damian Conway 的 PPR 使用正则表达式的这些特性来构建重要的(但仍然很小)解析树。
能力
a lot more capable
Raku“正则表达式”可以被视为对正则表达式展开演变的清理。在某种程度上,这有助于人们理解它们,太好了。
但实际上,这是一项全新的交易。例如,它们以一种合理的方式完成图灵,因此能够解析任何东西。
than officially admitted
好吧,这么说很奇怪! Raku 的语法经常被吹捧为 Raku 最具创新性的功能之一。
主要注意三点:
性能 当前的主要警告是,一个编写良好的 C 解析器将使一个编写良好的基于 Raku 语法的解析器大吃一惊。
回报 如果存在现有的解析器,那么为非平凡格式编写完全正确的解析器通常是不值得的。
左递归 Raku不会自动重写left recursion(无限循环)。
使用现有的解析器
I know there are BibTeX parsers around, but I need to grab the complete entry for further processing, and peek at a few keys meanwhile.
在 Raku 中使用外国模块可能有点启示。它不一定像您以前经历过的任何事情。 Raku 的外语适配器可以为您提供智能 marshaling,因此您可以像使用本地 Raku 功能一样。
两个可用的外语适配器已经完善得令人惊叹 -- 用于 Perl 和 C 的适配器。
我很确定有一个用于 Perl 的 BibTeX 包,它包装了一个 C BibTeX 解析器。如果您使用它,您有望将解析结果全部很好地包装到 Raku 对象中,就好像它一开始就是所有 Raku 一样,但保留了 C 代码的大部分高性能。
Raku BibTeX 语法?
也许您确实需要创建和使用小型 Raku Grammar。
(也许你这样做的部分原因是为了让自己熟悉 Raku,或者 Raku 的 regex/grammar 方面。因此,这听起来非常理想。)
一旦您开始同时使用多个正则表达式(即使只是两个),您就接近 grammar
领域了。毕竟,它们只是一起使用多个正则表达式的易于使用的结构。
因此,如果您决定坚持在 Raku 中编写解析代码,请期望编写如下内容:
grammar BiBTeX {
token TOP { ... }
token ...
token ...
}
BiBTeX.parse: my-bib-file
有关详细信息,请参阅 the official doc's Grammar tutorial 或阅读 Moritz 的书。
好的,刚刚(重新)检查过。 '{' ~ '}'
的文档留下了很多不足之处,它是用来处理 平衡的、正确嵌套的 定界符的。
所以我的最终解决方案实际上是这样的:
my regex nested-braces {
:ratchet
'{' ~ '}' .*
}
谢谢大家!今天学了不少东西
我需要匹配 BibTeX 文件中 key = value
对的值,它可以包含任意嵌套的大括号,由大括号分隔。我最多只能匹配两个深嵌套花括号,比如 {some {stuff} like {this}}
和 kludgey:
token brace-value {
'{' <-[{}]>* ['{' <-[}]>* '}' <-[{}]>* ]* '}'
}
我对再往下一层的想法感到不寒而栗......但是正确解析我的 BibTeX 内容至少需要三层深度。
是的,我知道周围有 BibTeX 解析器,但我需要获取完整的条目以进行进一步处理,同时还要查看几个键。我的 *.bib
文件相当乏味(我不介意手动处理一些零散的条目),问题是我有很多文件,而且有很多重叠。但是一些“相同”的条目有不同的键或额外的数据。我想将它们合并成几个主文件(BibTeX 背后的整个想法,对吧?)。如果 bibtool
给出一个大约 20,000 行没有重复(哈!)的文件...
在仔细阅读 Lenz 的“使用 Perl 6 正则表达式和语法进行解析”(Apress,2017 年)之后,我意识到“正则表达式”机制(基于回溯)实际上可能比官方承认的更强大,因为正则表达式可以调用另一个,我没有看到任何地方禁止 递归 调用。
在深入研究之前,了解一些上下文无关语法:描述嵌套大括号(仅此而已)的一种方法是使用语法:
S -> { S } S | <无>
即,嵌套大括号是左大括号、嵌套大括号、右大括号、更多嵌套大括号;或者什么都没有。这或多或少直接翻译成 Raku(没有空的正则表达式,通过使构造可选来伪造它):
my regex nb {
[ '{' <nb> '}' <nb> ]?
}
瞧,这行得通。需要修复以避免捕获,终止回溯(如果第一次尝试不匹配,它永远不会匹配),并用“其他任何东西”填充物装饰。
my regex nested-braces {
:ratchet
<-[{}]>*
[ '{' <.nested-braces> '}' <.nested-braces> ]?
<-[{}]>*
};
这与我的测试用例一致。
对于不太喜欢冒险的人,Perl 有 Text::Balanced
模块(以前称为 Perl 5,可使用 Inline::Perl5
从 Raku 调用)。不幸的是,在语法中对我没有直接用处。
解决方案
A way to describe nested braces (and nothing else)
假定一个名为 &R
的规则,如果我正在编写一个快速的小型一次性脚本,我可能会编写以下模式:
\{ <&R>* \}
如果我正在编写一个应该可维护的更大的程序,我可能会编写一个语法,并且使用名为 R
的规则,模式将是:
'{' ~ '}' <R>*
后者避免了leaning toothpick syndrome and uses the regex ~
operator.
这些都将解析任意深度嵌套的成对大括号,例如:
say '{{{{}}}}' ~~ token { \{ <&?ROUTINE>* \} } # 「{{{{}}}}」
(&?ROUTINE
指的是它出现的例程。正则表达式是例程。(虽然你不能在用 / ... /
语法声明的正则表达式中使用 <&?ROUTINE>
。 )
regex
对比 token
kill backtracking
my regex nested-braces {
:ratchet
用 regex
和 token
声明的模式之间的唯一区别是前者将棘轮 关闭 。所以使用它然后立即转动棘轮 on 是非常不合常理的。相反:
my token nested-braces {
回溯
the "regex" machinery (based on backtracking)
grammar/regex 引擎 包括 回溯作为一项 可选 功能,因为这有时正是人们想要的。
但是引擎不是“基于回溯”,许多grammars/parsers很少或根本不使用回溯。
递归
a regex can call another, and nowhere do I see a prohibition on recursive calls.
仅此一项对于现代正则表达式引擎来说并没有什么特别之处。
PCRE 自 2000 年起支持递归,自 2003 年起命名正则表达式。Perl 的默认正则表达式引擎自 2007 年起支持两者。
随着时间的推移,他们对更深层次的递归和更多命名的正则表达式的支持一直在增加。
Damian Conway 的 PPR 使用正则表达式的这些特性来构建重要的(但仍然很小)解析树。
能力
a lot more capable
Raku“正则表达式”可以被视为对正则表达式展开演变的清理。在某种程度上,这有助于人们理解它们,太好了。
但实际上,这是一项全新的交易。例如,它们以一种合理的方式完成图灵,因此能够解析任何东西。
than officially admitted
好吧,这么说很奇怪! Raku 的语法经常被吹捧为 Raku 最具创新性的功能之一。
主要注意三点:
性能 当前的主要警告是,一个编写良好的 C 解析器将使一个编写良好的基于 Raku 语法的解析器大吃一惊。
回报 如果存在现有的解析器,那么为非平凡格式编写完全正确的解析器通常是不值得的。
左递归 Raku不会自动重写left recursion(无限循环)。
使用现有的解析器
I know there are BibTeX parsers around, but I need to grab the complete entry for further processing, and peek at a few keys meanwhile.
在 Raku 中使用外国模块可能有点启示。它不一定像您以前经历过的任何事情。 Raku 的外语适配器可以为您提供智能 marshaling,因此您可以像使用本地 Raku 功能一样。
两个可用的外语适配器已经完善得令人惊叹 -- 用于 Perl 和 C 的适配器。
我很确定有一个用于 Perl 的 BibTeX 包,它包装了一个 C BibTeX 解析器。如果您使用它,您有望将解析结果全部很好地包装到 Raku 对象中,就好像它一开始就是所有 Raku 一样,但保留了 C 代码的大部分高性能。
Raku BibTeX 语法?
也许您确实需要创建和使用小型 Raku Grammar。
(也许你这样做的部分原因是为了让自己熟悉 Raku,或者 Raku 的 regex/grammar 方面。因此,这听起来非常理想。)
一旦您开始同时使用多个正则表达式(即使只是两个),您就接近 grammar
领域了。毕竟,它们只是一起使用多个正则表达式的易于使用的结构。
因此,如果您决定坚持在 Raku 中编写解析代码,请期望编写如下内容:
grammar BiBTeX {
token TOP { ... }
token ...
token ...
}
BiBTeX.parse: my-bib-file
有关详细信息,请参阅 the official doc's Grammar tutorial 或阅读 Moritz 的书。
好的,刚刚(重新)检查过。 '{' ~ '}'
的文档留下了很多不足之处,它是用来处理 平衡的、正确嵌套的 定界符的。
所以我的最终解决方案实际上是这样的:
my regex nested-braces {
:ratchet
'{' ~ '}' .*
}
谢谢大家!今天学了不少东西