如何使用更通用的数据结构?

时间:2012-05-23 19:31:01

标签: c++ parsing

我正在尝试创建一个允许有限的用户定义替换规则的文本解析器。

即使我正在读取DOS ASCII文件中的代码,其中订购很重要并且必须保持行编号。使用此输入,我想应用用户定义的替换规则(为该字符串交换此字符串,如果我们看到此字符串后跟该字符串执行此转换等)。

输出也是格式化的DOS ASCII文件。

大多数规则都是直接替换针对tat类型的替换,但是,在某些情况下我想要定义一个规则,例如如果A在将来的任何时间点后面跟着B,请应用此规则。

要做到这一点,我正在使用结构树本身:

struct node {
    list<string> common;  // the text which is not affected by conditions
    string condition;     // matching this string selects the left, otherwise the right
    node *lptr, *rptr;    // pointers to the child nodes, if needed
};

每当我遇到这样的规则时,我都可以通过省略和应用规则来维护输出,从而延迟决定使用哪个直到明确地解决它。

这有点浪费内存,但似乎是避免必须两次传递输入数据的最佳方法(输入数据的大小未知,但可能不到1兆)。

当然可能存在这样一种情况:这种类型的不同规则在一个或两个子节点内触发,这就是树结构的原因。

没有限制孩子必须在父母面前做出决定,可能是父母只能在孩子的一个分支上进行决定。遇到EOF会让任何未定的孩子处于错误的方向。

所以很明显我在倒带和折叠节点时一定要小心。

这个一般性问题是否有更简单的解决方案?有没有办法以比我的树更有效的方式使用标准库容器?

3 个答案:

答案 0 :(得分:0)

您可能需要查看NFA和DFA,即非确定性有限状态自动和确定性有限状态自动。这两种方法是编写器解析器最常用且通常非常有效的方法。

实际上不需要将数据存储在节点中,否则它将被传递并浪费内存。更好的方法是,分配一个变量(比如int state = 0)来跟踪当前的解析状态。根据当前状态和输入,您的算法将改变状态。状态总是向前发展,但如果某个条件不匹配(称为“回溯”),您可以告诉您的算法返回到之前的状态。

E.g。如果“ab”和“ac”是两个有效输入,解析“ac”时算法可能是这样的:

char is 'a' ==> go to state.checkB
char is not 'b' ==> go back to state.checkA
checkB was already done ==> go to state.checkC
char is 'c' ==> DoSomething();

需要大量的文章和图表来完整地解释所有内容,希望这能让您知道在哪里进一步了解。

答案 1 :(得分:0)

假设通过'文本解析器',你的意思是你试图压缩相同含义的单词和短语,以简化对命令的反应。

在这种情况下,根据旧的文本冒险程序,使用规则查找表的简单左右解析器可以在这里工作。

除非我误解了您的问题域,否则您的解决方案似乎过度设计了。

答案 2 :(得分:0)

听起来你应该试试正则表达式。以下是有关选择图书馆的讨论链接:C++ RegEx Library Choice。 Boost很受欢迎。

另外,您是否考虑过使用其他语言来解决问题? Python有一个很好的有用库库,包括一个用于正则表达式(import re)。如果它在您的驾驶室中,您可能会发现它比C ++解决方案更容易。

最后,考虑使用“已定义”的文本格式而不是输入文件的自定义格式。 XML是一个不错的选择。在XML树中嵌套规则可能更容易。 C ++你可以使用Expat XML Parser(Python将是xml.etree.ElementTree)。