【问题标题】:Extracting information using BNF grammars使用 BNF 语法提取信息
【发布时间】:2012-06-12 14:20:57
【问题描述】:

我想从正文中提取信息并能够查询它。

此文本正文的结构将由 BNF 语法(或变体)指定,要提取的信息将在运行时指定(查询的语法此时无关紧要)。

所以要求很简单,真的:

  • 接收一些结构化的文本正文
  • 使用语法以可利用的形式加载它并对其进行解析
  • 运行查询以选择其中的某些部分

举个例子,假设我们有这样的语法(定制的 BNF 格式):

<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<id> ::= 15 * digit

<hex> ::= 10 * (<digit> | a | b | c | d | e | f)

<anything> ::= <digit> | .... (all characters)

<match> ::= <id> (" " <hex>)*

<nomatch> ::= "." <anything>*

<line> ::= (<match> | <nomatch> | "") [<CR>] <LF>

<text> ::= <line>+

这样的文本将符合哪些条件:

012345678901234
012345678901234 abcdef0123

Nor the previous line nor this one would match

然后我想列出规则中出现的所有标签,例如使用类似 XPath 的语法:

match//id

这将返回一个列表。


这听起来相对容易,除了我有两个很大的限制:

  • 应在运行时读取 BNF 语法(从类似字符串/向量的结构)
  • 查询也将在运行时读取

一些精度:

  • 预计语法不会经常更改,因此生成内存结构的“编译”步骤是可以接受的(并且可能是实现良好速度所必需的)
  • 速度至关重要,即时收集所需部分的奖励积分
  • 可以通过回调消除歧义的可能性(例如,有时必要的歧义消除信息可能需要访问数据库)
  • 多部分语法的加分项(有利于语法元素的模块化和重用)

例如,我知道 lex/yacc 和 flex/bison,但是它们似乎只创建要编译的 C/C++ 代码,这不是我所关心的。

您是否知道一个强大的库(最好是免费和开源的),它可以“即时”将 BNF 语法转换为解析器,并使用该解析器从文本体中生成结构化的内存输出?

编辑:我对替代品持开放态度。目前的想法是,也许正则表达式可以允许这种提取,但是考虑到所涉及的语法的复杂性,这可能会很快变得丑陋,因此维护正则表达式将是一项非常可怕的任务。此外,通过分离语法和提取,我希望能够针对不同的提取需求重用相同的语法,而不是每次都有稍微不同的正则表达式。

【问题讨论】:

  • 如果一切都失败了,请在 Boost.Spirit 中编写解析器生成器。 ;-) 带有模板元编程的元元。
  • 我认为这是部分欺骗:stackoverflow.com/questions/7392302/…。它仅涵盖解析器生成,而不是针对此问题的其他详细信息。它没有“是的,这是一个链接”形式的答案。所以我并不是说这个问题是多余的。
  • 看起来您正在尝试构建一个正则表达式机器(如果我错了,请纠正我)。如果您愿意,请尝试使用状态机。
  • 我有一个您可能感兴趣的compiler library。它会即时读取语法,创建语法表并将其缓存,因此重新运行很快。输入格式不是 BNF,必须通过动作例程进行语义分析。我用 C++ 写的又快又脏,所以实现看起来可能不太漂亮。它接受模棱两可的语法,但您只能在表创建期间解决,而不是在解析时解决。几个月后,我会用更好更快的子结构用 C 重写它,但它的用法不会有太大的不同。
  • @dirkgently 不,它不是正则语法(可以用正则表达式来描述),它是上下文无关的语法。虽然,他可以使用状态机带有堆栈。

标签: c++ parsing bnf information-extraction


【解决方案1】:

我有一个专有的解决方案,可以将语法源转换为内存中的表示。结果是一个纯数据结构。任何代码都可以使用它。我也有实际实现解析器的 C++ 类。规则处理程序被实现为虚拟方法。

我们的解决方案与 YACC/Bison 的主要区别在于不生成 C/C++ 代码。这意味着可以在不重新编译应用程序的情况下重新加载语法。语法可以使用在规则处理程序代码中使用的应用程序 ID 进行注释。

【讨论】:

  • 感谢您的回答,我需要一些时间来准确检查一下,同时 +1 已经提供了一个有希望的答案。
  • 我查看了该站点,但找不到相应的代码。是否可以查看此解析器的一些文档/API?事实上,我很难在这方面发表自己的看法......
  • 马修,给我你的电子邮件地址。我会给你一些信息。那里的源语言与 YACC 相似,但不完全相同。源语法示例位于cdsan.com/GraCpp_Grammar.php。源语法既可以从磁盘文件中获取,也可以从内存缓冲区中获取。
  • 谢谢,我没有看到语法:) 我已经通过网站联系表发送了一封电子邮件。
  • 马修,请讲道理。我说的不是一般的语法,你已经看过很多次了,而是关于特定语法定义语言中的示例,该语言具有描述冲突的部分(、、 等)。我不确定是否有任何其他语法定义语言具有预期语法冲突的概念。
【解决方案2】:

GOLD 解析器系统生成一个 LALR 解析表,该表在运行时显然已加载 AFAIK。我相信它有一个 C++“解析”引擎,所以应该很容易集成。

您会阅读您的语法,派生一个子进程以让 GOLD 解析器生成器生成表,然后调用您的有线 GOLD 解析器进行加载和解析。

我不知道您如何将 操作 附加到减少中,您可能想要这样做。 我对 GOLD 没有具体的经验。祝你“黄金”好运。

【讨论】:

  • 如果可能的话,我希望能够将“验证”操作附加到某些项目,但这可以在以后处理。只要我能有效地提取信息,我就会有外部代码来处理这些信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-03
  • 2021-06-04
相关资源
最近更新 更多