如何将二进制表达式树从字符串转换为嵌套列表



我最初的问题是理解我试图做的是什么。我真的不知道如何搜索帮助,因为我并不真正理解这就是我试图做什么。我在回答中详细解释了我做了什么,以及我是如何做的。我还发布了我的代码。

在用C#构建PowerShell之前,我花了一段时间在PowerShell中进行原型设计。我希望这对其他人有帮助。

问题:

如何将"(Foo1 && Bar1 && (Foo2 || Bar2) && (Foo3 || Foo4))"这样的字符串转换为这样的列表

[
["Foo1", "Bar1", "Foo2", "Foo3"],
["Foo1", "Bar1", "Foo2", "Foo4"],
["Foo1", "Bar1", "Bar2", "Foo3"],
["Foo1", "Bar1", "Bar2", "Foo4"]
]

将二进制表达式树的字符串表示转换为所有可能组合的嵌套字符串列表我试图构建一个类,该类允许我将字符串格式的二进制表达式树(请参阅下面的输入示例)转换为所有可能的值组合的嵌套列表。刚开始的时候,我不知道这是一个二进制表达式树,所以我真的不知道如何找到我要找的东西。

注意:我没有接受过正式的CS培训,也没有接受过正规的编程教育。我是作为一名系统管理员进入IT行业的,除了十几岁时用C++进行过短暂的编程外,多年的HTML/CSS从未真正破坏过编译软件。我写了很多脚本,花了大约五年的时间掌握PowerShell——这仍然是我最舒服的地方。我的大部分原型设计都是在PowerShell(7.1.3)中完成的。

您可以在github上查看我的代码。

输入示例

示例1

"(param_1 && param_2 && (param_3 || param_4) && (param_5 || param_6 || param_7))"

示例2

"((param1 && (param2 || param3 || param4)) && param5)"

示例3

"(param1 || (param2 && param3 && param4 && (param5 || param6 || param7)))"

预期输出

示例1

[
["param_1","param_2","param_3","param_5"],
["param_1","param_2","param_3","param_6"],
["param_1","param_2","param_3","param_7"],
["param_1","param_2","param_4","param_5"],
["param_1","param_2","param_4","param_6"],
["param_1","param_2","param_4","param_7"]
]

示例2

[
[
["param1", "param2", "param5"],
["param1", "param3", "param5"], 
["param1", "param4", "param5"]
]
]

示例3

[
[
["param1"],
["param2", "param3", "param4", "param5"],
["param2", "param3", "param4", "param6"],
["param2", "param3", "param4", "param7"]
]
]

在这一过程中有一些痛点——当我试图解决问题时,我被卡住了,最终重复了工作

将字符串转换为二进制表达式树在我从库中找到我想要的东西之前,我已经花了相当多的时间来构建一个解析器,将字符串转换为二进制表达式树。

解决方案

最终,我找到了NRECO的LambdaParser库(github),这减轻了很多压力(尽管我很确定我所构建的在这个意义上是完整的)。

意外边缘情况

虽然这看起来微不足道,但我在树上构建列表时不断遇到问题。

左成员中的多重相似表达式最初,我没有考虑左成员包含多个类似表达式的情况(ie"this AND that AND that too"),这导致构建不完整的列表。

节点不包含成员表达式(?)

我以为我已经完成了这个工具。我得到了一份可能的表达式列表(除了我一直在测试的少数表达式之外),然后。。。它内爆了。我发现我没有考虑到当前处理节点包含两个二进制表达式的情况。(而到目前为止,我构建它的印象是,一方或另一方总是一个成员表达式)

一旦我遇到这个问题,我就意识到哪里出了问题,并且已经花了很多时间在这件事上,我知道需要做什么,只是不太清楚我该怎么做。

解决方案

当出现其中一个节点时,我必须根据深度上最接近下一个成员表达式的表达式创建两个分叉路径。从那里它将创建两条路径,在相反的节点上向下处理,直到到达"0";底部";。我们可以将每条路径的每次迭代添加到主输出中。假设此函数是递归的,则无论发生多少次,都不应该

注意:在我的解决方案中,当遇到不包含成员表达式的二进制表达式时,当前仍然假设两个表达式中的一个将是成员表达式。也就是说,如果我理解这种表达的本质,我认为这不应该是一个问题

注意:我找到了一些参考资料,包括这个关于做类似F#的问题,但我似乎无法将其应用于我的问题。

密钥获取

对我来说,这是一次非常有用的学习经历,在这次学习中,我遇到了一个涉及核心数据结构的现实世界问题。由于我没有(编程)算法或数据结构的真正背景,这教会了我很多,尽管它是一个巨大的PITA,但它教会了我许多关于如何在未来解决这些类型的问题。如果你有时间的话,我鼓励任何人尝试自己建造这个。感谢阅读。

最新更新