数据翻译/转换是不是有好的模式/习语?
Posted
技术标签:
【中文标题】数据翻译/转换是不是有好的模式/习语?【英文标题】:Are there good Patterns/Idioms for Data Translation/Transformation?数据翻译/转换是否有好的模式/习语? 【发布时间】:2009-08-05 12:29:16 【问题描述】:我很抱歉这个问题的通用标题,但我希望我能够不那么笼统地表达它。 :-
我想编写一个将输入标记流转换为输出标记流的软件(在本例中使用 C++)。只有五个输入标记(我们称它们为 0、1、2、3、4),每个标记都可以有几个不同的属性(例如,可能有一个 4.x 属性或 0.foo)。还有一些输出标记,大约十个,我们称它们为(Out0..Out9),它们每个都有一些属性。
现在,我们一直在研究从输入标记到可能的输出标记的序列映射,如下所示:
01 -> Out0
34 -> Out1
0101 -> Out3
...所以不同的输入标记序列映射到单个输出标记。
在我的场景中,输入标记集是固定的,但输出标记集不是固定的——我们可能会决定引入新的“产品”。我的问题是:
有谁知道在这种情况下是否有好的模式和/或习语有帮助?
现在我有一组“压缩器”对象,每个对象都可以吃掉输入令牌并最终产生输出令牌。问题是某些输入标记发生冲突,在上述情况下考虑“Out0”和“Out3”。输入“0101”应该产生 Out3 但不是 Out0。但是,输入 '0104 应该产生 Out0,然后将 0 和 4 留在队列中。
我想知道是否存在来自数据压缩或其他可能有益的模式。
这种将低级标记的输入“减少”为高级标记并处理可能的冲突的工作在解析器编写者中很常见,不是吗?那里有有用的模式吗?
更新:
更多信息:
在我的具体情况下,输入标记是 C 结构,输出标记是 C++ 对象。我无法控制令牌的输入流,但我可以将它们排队,然后修改队列以防万一。
我通过尝试先匹配 Out3 然后匹配 Out0 解决了冲突(如 Out3 (0101) 与 Out0 (01)),但它有点难看。可能的产品在一个列表中,我只是尝试将它们一个接一个地应用于输入流
用户可以扩展可能产生的列表,因此我无法生成一个巨大的 DAG,然后拥有一个状态机来实现它来处理每个可能的转换。当然,这意味着用户可以添加碰撞,但这就是它的方式。
【问题讨论】:
那么它怎么知道0101不是2 Out1s呢? 现在,在检查输入事件队列是否可以压缩时尝试规则的顺序很重要。所以'Out3'必须比'Out0'更早出现在列表中。它不是很优雅,但到目前为止对我来说还不错。 实际上,将输入流分成标记不是解析器的工作,而是词法分析的工作。你需要一个词法分析器。但是,只要您不说如何判断0101
不是两个 Out1
s,我们就不知道词法分析器应该如何工作。
@sbi 我相信输入标记'0,1,2,3,4'是否已经是'标记'或者它们是否比这更低级并且需要被词法分析器使用。
我认为这个定义很清楚。解析器被赋予一系列单独的标记。它不需要担心每个令牌的开始和结束位置。词法分析器是负责确定这一点的人。无论如何,在我看来,最好的选择就是使用 Flex 之类的工具,或者 Boost.Spirit。编写一个词法分析器来处理它。
【参考方案1】:
您可以定义一个图,其中每个节点都包含一个输入标记和一个关联的输出。每个节点的链接描述了可能的下一个标记。因此,图中的一条路径描述了一个可能的转换规则。
要转换数据,从与第一个输入标记对应的节点开始,并尝试在可能的最长路径上导航图,将下一个输入标记与链接到当前节点的节点匹配。当没有链接节点与下一个输入节点匹配时,将与当前节点关联的输出作为结果。
【讨论】:
是的,这个“最长的比赛获胜”的想法是另一种选择。到目前为止,我手动对规则的尝试顺序进行了排序——这对我来说已经足够好了(但也许它的扩展性不够好,我不知道)。 查看更新后的问题,了解为什么我无法定义一张大图。【参考方案2】:在设计数据压缩算法时,您需要注意不能将一段代码的开头误认为是另一段较短的代码。这是Hamming code 的基础。另一种选择是使用分隔符分隔您的标记,例如摩尔斯电码(在字符之间使用短暂的停顿)。
【讨论】:
【参考方案3】:几年前我会立即说看看 Bison http://www.gnu.org/software/bison/ 或 Yacc,但我已经有一段时间没有做过这样的事情了,所以不知道有没有更好的。
对于您正在做的事情来说,使用它们可能有点过头了,但使用的成语可能很有用。
【讨论】:
是的,感觉很像解析,不过我需要更通用的东西——可以将一组输入结构解析成输出对象列表的东西。以上是关于数据翻译/转换是不是有好的模式/习语?的主要内容,如果未能解决你的问题,请参考以下文章
在字典中添加新列表或附加到列表(如果存在)是不是有一个很好的习语?
是否有 JavaScript 习语将“未定义”更改为“空”?