【问题标题】:Parsing: library functions, FSM, explode() or lex/yacc?解析:库函数、FSM、explode() 还是 lex/yacc?
【发布时间】:2011-04-17 22:03:39
【问题描述】:

当我必须解析文本(例如配置文件或其他相当简单/描述性的语言)时,我想到了几种解决方案:

  • 使用库函数,例如strtok(), sscanf()
  • 一种有限状态机,一次处理一个字符,进行标记和解析
  • 使用 explode() 函数,我曾经纯粹是因为无聊而写的
  • 使用lex/yacc(阅读:flex/bison)生成适当的解析器

我不喜欢“库函数”方法。感觉很笨拙和尴尬。 explode(),虽然不需要太多新代码,但感觉更加炸了。而flex/bison 常常显得过于矫枉过正。

我通常会实现一个 FSM,但同时我已经为这个可怜的家伙感到抱歉,因为他们以后可能不得不维护我的代码。

因此我的问题是:

解析相对简单的文本文件的最佳方法是什么?
这有关系吗?
是否有普遍认可的方法?

【问题讨论】:

  • 为什么你觉得 flex/bison 过大了?它们当然可以很容易地用于解析配置文件或简单的语言。我通常使用自制的 C++(或适用时的 C)解析器来解析我的配置文件,但我总是后悔。不过,使用正则表达式库可能会让您倾向于临时解析。对于配置文件,请查看 libconfig。

标签: c parsing lex explode scanf


【解决方案1】:

我要打破规则,乱回答你的问题。

  • 是否有普遍认可的方法?

绝对不是。恕我直言,您选择的解决方案应该取决于(仅举几例)您的文本、您的时间框架、您的经验,甚至您的个性。如果文本简单到足以使flexbison 过分杀伤力,那么可能C 本身就是过分杀伤力。快速还是健壮更重要?它是否需要维护,还是可以快速而肮脏地启动?您是热情的 C 用户,还是会被正确的语言特性所吸引? &c., &c.

  • 这有关系吗?

再说一次,这是只有你才能回答的问题。如果您正在与具有特定技能和能力的团队密切合作,并且解析器很重要并且需要维护,那么它确实很重要!如果您正在“纯粹出于无聊”而写一些东西,我会建议这根本不重要,不。 :-)

  • 解析相对简单的文本文件的最佳方法是什么?

嗯,我不知道你会喜欢我的回答。也许先在这里阅读其他一些很好的答案。

不,真的,继续。我等着。

啊,你回来了,放松了。让我们放松一下,好吗?

如果可以在 'awk' 中完成,切勿将其写在 'C' 中;
如果 'sed' 可以处理,切勿在 'awk' 中执行此操作;
当“tr”可以完成工作时,切勿使用“sed”;
当 'cat' 足够时,切勿调用 'tr';
尽可能避免使用“猫”。
-- 泰勒编程定律

如果你用 C 编写它,但 C 感觉像是错误的工具……它确实可能是错误的工具。 awkperl 很可能会做你想做的事情,而不会引起任何麻烦。您甚至可以使用 cut 或类似的东西来做到这一点。

另一方面,如果你用 C 编写它,你可能有充分的理由用 C 编写它。也许你的解析器只是一个更大系统的一小部分,为了论证,嵌入,在冰箱里,在月球上。或者,也许你喜欢 C。你甚至可能讨厌 awkperl,上帝保佑。

如果您不讨厌awkperl,您可能希望将它们嵌入到您的C 程序中。原则上这是可行的——我自己从来没有做过。对于awk,请尝试libmawk。对于perl,可能有几种方法(TMTOWTDI)。您可以使用popen 单独运行perl 来启动它,或者您可以将Perl 解释器实际嵌入到您的C 程序中——参见man perlembed

无论如何,正如我所说,“解析的最佳方式”完全取决于您和您的团队、问题空间以及您解决问题的方法。我能提供的就是我的意见。

我将假设在您的纯 C 解决方案(库函数和 FSM(考虑到您的 explode 本质上是一个库函数))中,您已经尽力隔离相关代码,设计代码和文件,等等。

即便如此,我还是要推荐lexyacc

图书馆功能感觉“笨拙和尴尬”。状态机似乎无法维护。但是你说lexyacc 感觉有点矫枉过正。

我认为您应该以不同的方式处理您的投诉。你真正在做的是指定一个 FSM。但是,您还聘请了某人为您编写和维护它,从而解决了大部分可维护性问题。矫枉过正?我有没有提到他们会免费工作?

我怀疑,但不知道,lexyacc 最初感觉有点矫枉过正的原因是你的配置/简单文件感觉太简单了。如果我是对的(一个很大的如果),您也许可以在词法分析器中完成大部分工作。 (甚至可以想象,您可以在词法分析器中完成所有工作,但我对您的输入一无所知。)如果您的输入不仅简单而且广泛,您也许可以免费找到一个词法分析器/解析器组合,用于什么你需要。

简而言之:如果您不能在 C 中做到这一点,请尝试其他方法。如果你想要 C,请使用 lexyacc——它们有一点开销,但它们是一个非常好的解决方案。

【讨论】:

    【解决方案2】:

    如果你能让它工作,我会选择 FSM,但在 Perl-compatible regular expressions 的大力协助下。这个库很容易理解,你应该能够修剪掉足够多的多余意大利面,让你的怪物具有所有飞行怪物都渴望的空气动力学天赋。那,以及结构良好的意大利面条中的大量 cmets,应该让您的代码维护继任者感到舒适。 (而且,我相信你知道,那个代码维护的继任者是 六个月后,当你转向其他事情并且这段代码的细节已经忘记了。)

    【讨论】:

    • 我的 FSM 通常类似于 while(c = nextc()) switch(c) {...}。我不认为它们是意大利面怪物,只是……很大。话虽如此,我从未在 C 中使用过 RE 并且拒绝这样做。 :>
    【解决方案3】:

    我的简短回答是对问题也使用正确的。如果您有配置文件,请使用现有的标准和格式,例如ini 文件并使用Boost program_options解析它们。

    如果您进入“自己的”语言世界,请使用lex/yacc,因为它们为您提供所需的功能,但您必须考虑维护语法和语言实现的成本。

    因此,我建议您进一步缩小问题范围以找到合适的工具。

    【讨论】:

    • Boost 的问题在于它是 C++ 代码而不是 C 代码,而且问题确实询问了 C。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多