【问题标题】:How are textual data files parsed in modern C++?现代 C++ 中如何解析文本数据文件?
【发布时间】:2011-11-04 09:43:13
【问题描述】:

我(也)经常面临必须解析文本数据文件的任务——在“每个人”都使用 XML 之前你使用的那种文本结构化数据表示——这是某种行业标准。 (这些太多了。)

无论如何,基本任务始终是获取一个文本文件并将其中的内容填充到某种数据结构中,以便我们的 C++ 代码可以处理这些信息。

现在,我已经手动实现了一些简单的(而且有很多错误的)解析器,我鄙视的几乎没有。 :-)

所以 - 我想知道当我想将结构化文本数据“解析”成内存中的表示形式时,当前的技术状态是什么(想想:任意语言的 XML 数据绑定)。

到目前为止,我发现的是“What parser generator do you recommend”,但我不太确定我是否在使用解析器生成器(如 ANTLR)。

明显的候选者似乎是pegtlBoost.Spirit,但它们看起来都相当复杂(但至少它们是在语言中的),上次我尝试 Spirit 时,编译器错误让我抓狂。 (并且 pegtl 需要一个与 C++11 兼容的编译器,这仍然是一个问题(VC++ 2005)。)

所以我错过了一个更简单的解决方案只是为了得到类似的东西

/begin COMPU_METHOD
  DEC "  Decimal value"
  RAT_FUNC
  "%3.0"
  "dec"
  COEFFS 0 1.000000 0.000000 0 0.000000 1.000000
/end COMPU_METHOD

到 C++ 数据结构中? (这只是一个任意示例,说明此类文件的一部分可能看起来如何。对于 这种 格式,我可以(并且可能应该)购买一个库来解析它,因为它已经足够广泛了——我遇到的所有格式都不是这样。)

-- 或者我应该只考虑 Boost.Spirit 的复杂性

【问题讨论】:

  • boost.spirit 并不比任何其他 (E)BNF 使用工具复杂得多。如果您想反映文件的完整语法(如果有的话)或者只是“获取”一些信息,这里的问题可能更多。完整语法的优点是在手工编码的解析代码中误解文件格式的逻辑错误更少。
  • 文本文件的格式是否已经定义且不可更改,或者您是否允许定义或更改文本文件的格式?
  • @rve - 不,格式始终是固定的,来自第 3 方。
  • 4 年过去了,如果您有兴趣,我们“刚刚”在github.com/ColinH/PEGTL 发布了一个新的和大大改进的 PEGTL 版本,它应该可以与 VS2015 一起使用
  • @Daniel - 太棒了!我们在 VS2015 上……不。等待 2005:20_0_5 ... 叹息 :-)

标签: c++ parsing boost-spirit dataformat


【解决方案1】:
  • 提振精神

  • Coco/R (C++)

    我使用这个非常实用的解析器生成器取得了很好的效果,它支持许多使用通用语法格式的语言/平台。 解析速度与 Boost Spirit 不相上下(尽管使用泛型编程处理解析数据的效率可能更高)

编辑为了让事情变得非常清楚,我从来没有用 Coco/R 做不到的事情。

但是,我真的沉迷于 Spirit 为我推断属性类型(转换)的轻松一般。这是主要的节省时间。但这会涉及到成本:

  • 学习曲线,维护
  • 编译时间(但解析器不经常改变)

【讨论】:

    【解决方案2】:

    我强烈建议硬着头皮使用 Boost.Spirit。尽管错误信息足以让人脑洞大开,但这对我来说是值得的。我已经用它在几个小时而不是几天内为未记录(或未记录)的自定义文件格式实现了解析器。

    我发现处理它的最佳方法是将其视为“类固醇上的std::istream”,因为它使用相同的双角符号来表示分离。

    【讨论】:

      【解决方案3】:

      你没有提到你手工创建的解析器有多复杂。但我相信,只要您将工作拆分为由专用状态机执行的词法和句法解析,那么这些简单的文件肯定可以通过手工制作的例程进行解析。第一个识别标记,例如您的示例关键字、数字和字符串,并将它们提供给第二个尝试识别更长的句子并创建相应的数据结构。使用遵循常规语法的简单文件,没有歧义和其他冲突,它应该非常简单且易于管理。

      【讨论】:

      • 他们并不复杂。它们有问题(没有完全解析所有可能的输入),有蹩脚的错误消息(如果有的话),通常很慢(手动动态分配太多),搞砸了空格和字符串处理,被 cmets 弄糊涂了——我可以在这里继续。手动编写解析器(通过读取文件、遍历缓冲区等)是我能想到的最可怕、最容易出错和无法维护的事情。我知道这就是“我自己”,也有人对此感到高兴,但我宁愿不这样做。谢谢你。 :-)
      • @Martin:自动解析器(如 Spirit 或 YACC)通常也没有很好的恢复。我见过的唯一具有良好错误恢复能力的解析器是手工制作的,它们使用启发式来“猜测”输入应该是什么。
      • 我想你试图一步完成太多事情。我认为您可以查看 lex 或派生实用程序。它从常规语法描述生成一个 C 函数,该函数处理您描述的问题,例如匹配标记、消除 cmets 和空格。它是一个外部实用程序,但每次语法修改只需使用一次。
      • @jszpilewski - 我们在绕圈子吗? :-) 我在最初的问题中说我不确定解析器生成器是否是正确的工具/然后您回答“手动创建”可能足够好/然后您似乎推荐@据我所知,987654321@ 是一个解析器生成器...?
      • @Martin 不是一个完整的解析器,而只是一个词法分析器,它创建仍然需要组合成语法语句(如配置行)的标记。但它是一个单一的功能,它可以解决你提到的 cmets 等问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-25
      • 1970-01-01
      • 2015-01-07
      • 1970-01-01
      • 2022-06-15
      • 2015-12-31
      • 1970-01-01
      相关资源
      最近更新 更多