【问题标题】:Finding a substring token in a string in C++在 C++ 中的字符串中查找子字符串标记
【发布时间】:2010-12-03 23:17:04
【问题描述】:

好吧,假设我正在解析一些 XML(阅读任何“语言”时都会出现问题,但 XML 是许多人都熟悉的一种)。

XML 如下所示:

<Tag>
  <[CDATA[ blah blah]]>
  <Tag2>
    <Tag3/>
  </Tag2>
<Tag>

现在我想在该流中找到各种标记。重要的令牌如下(请原谅我蹩脚的“令牌”名称;))。

<           = Open Token
<[CDATA[    = Open CDATA Token
]]>         = Close CDATA Token
<!          = Open Comment Token
/>          = Close Open Token
</          = Open Close Token
>           = Close Token

我遇到的问题是我有一个上述的数组,并且我试图在逐个字符地读取文件时正确识别上述令牌之一。

所以我读到了第一个字符'

同样在完成标签时,例如“/>”。我读了第一个字符,我得到了'/'。这与“关闭打开令牌”相匹配。但它不完整,所以我应该检查下一个字符,在这种情况下是 '>' 给我“/>”,它与关闭令牌匹配。

我的问题是,当这些令牌的数量显着增加时,很难跟踪可能的匹配项是什么。有没有一种优雅的方式来做到这一点?或者我应该只是当我遇到一个“标记字符串”的第一个字符时将该标记推到一个向量上,然后只在后续读取时检查这些标记?如果下一个字符不匹配,那么我可以清除标记列表,然后重新开始。

这是解决问题的正确方法吗?有没有更好的办法?

(编辑:请不要将我指向 Lexx、YACC 等...我正在尝试在这里学习一些基础知识)

任何帮助将不胜感激:)

【问题讨论】:

  • 您所指的问题称为前瞻和回溯。我认为,如果您想要构建解析器的优雅解决方案,那么您应该检查功能解析器和解析器组合器:这可以让您构建一个主要声明语法生成规则的解析器。

标签: c++ xml parsing tokenize


【解决方案1】:

您需要在解析器中跟踪状态 - 我现在在哪里?接下来我期待什么? - 以特定于上下文的方式。当您看到接下来会得到什么时,您可以对照当前状态的有效值列表检查它,并可能存储已完成解析的数据项,并可能更改状态。

仅解析 XML看起来很容易 - 如果您真的想自己手动完成这项工作,有很多特殊情况需要处理。您的解析器是 Finite State Machine,但这是一个不平凡的例子。

【讨论】:

  • 干杯史蒂夫我一直在考虑把它分解成一棵树,这样我就知道可能的下一个状态是什么......
【解决方案2】:

我最近一直在做很多这种类型的解析(主要是使用 C#)。

我不确切知道您要完成什么,所以我不确定这有多大帮助,但我会解析整个事情并将其存储在某种数据数组中。

找到开始标签。然后解析接下来出现的任何文本(您知道何时到达文本的末尾,因为您将点击空格或标点符号)。

您可以对“!”进行特殊测试并且可能在找到它时在您的数据结构中设置一个标志。我发现快速扫描已知序列是不切实际的。您需要逐个字符地分解整个事物。

您可以在 http://www.softcircuits.com/Blog/post/2010/02/07/Parsing-HTML-Tags-in-C.aspx 看到我的 C# 结果之一。

【讨论】:

    【解决方案3】:

    解析是一个众所周知的问题,但这并不意味着它很容易编程。 你可以自己写任何东西,但正如你所遇到的,这很快就会变得相当复杂。

    您可以使用 Boost.Spirit 库,它非常大,可能需要一些时间才能掌握。

    或者作为替代方案,使用Lex / Yacc(或类似的东西)来生成解析器和词法分析器。 (这比 C++ 更像 C,但这当然不一定是坏事)

    我个人会花时间学习精通 Boost Spirit 库,虽然一开始可能看起来很多工作,但从长远来看,你会节省很多时间和头痛。手动解析类似 XML 的语言需要做的工作比您最初预期的要多。

    【讨论】:

    • @Goz 很公平,那么我认为你最好的选择是某种有限状态机,祝你好运,你肯定在正确的轨道上
    【解决方案4】:

    您可以让flex 为您执行此操作。更好的是,为您的语言挖掘现有的 XML 解析器——我相信现在已经有人实现了它。

    【讨论】:

    • 我很清楚这些事情。我不使用它们,因为我正在自学新技巧......
    • @Goz:这并不意味着它不能有效地回答这个问题。如果您知道这些事情并且不想将它们作为答案,那么您应该将其放在您的问题中。
    猜你喜欢
    • 2013-06-01
    • 1970-01-01
    • 2013-05-31
    • 1970-01-01
    • 2012-11-10
    • 2015-06-10
    • 2019-02-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多