Python 解析给定格式的字符串以构建二叉决策树

Python 解析给定格式的字符串以构建二叉决策树,python,parsing,binary-tree,Python,Parsing,Binary Tree,我试图解析一个带有括号的字符串,其形式为((问题)(左节点)(右节点)) 例如,问题的形式是“如果段大小

我试图解析一个带有括号的字符串,其形式为
((问题)(左节点)(右节点))


例如,问题的形式是“如果段大小<1.5,则选择左节点,否则选择右节点”。问题可以是一个带有键和值的字典。左和右节点表示一个完整的左或右半树,将递归遍历该树,直到到达叶节点。通过这种方式,我们将构建一个二叉决策树。

如果您可以决定输入格式的细节,那么使用原始python源代码。例如,您可以将树存储在节点的python字典中:

tree = {
    "root": ("a", "b")
    "a": ("c", "d"),
    "b": ("e", "f"),
    "c": (None, None), #No children, a leaf.
    "d": (None, None),
    "e": (None, None),
    "f": (None, None),
}
现在,您可以简单地使用python解析器解析此树

from tree_data import tree #We're done parsing!

root_node = tree["root"]
left_child = tree[root_node[0]]

如果已经指定了输入格式,那么如果您不共享该格式的详细信息,我们将无法帮助您。

如果您可以决定输入格式的详细信息,那么请使用原始python源代码。例如,您可以将树存储在节点的python字典中:

tree = {
    "root": ("a", "b")
    "a": ("c", "d"),
    "b": ("e", "f"),
    "c": (None, None), #No children, a leaf.
    "d": (None, None),
    "e": (None, None),
    "f": (None, None),
}
现在,您可以简单地使用python解析器解析此树

from tree_data import tree #We're done parsing!

root_node = tree["root"]
left_child = tree[root_node[0]]

好的,如果已经指定了输入格式,那么如果您不共享该格式的详细信息,我们将无法为您提供帮助。

这种语法确实是pyparsing的目标。基本格式非常简单,在pyparsing中,它看起来像:

decision = '(' + '('+question+')' + '('+action+')' + '('+action+')' + ')'
但一旦你开始添加算术表达式、布尔运算以及对“and”和“or”运算符的支持,事情就会变得复杂起来。此外,这是一种递归语法,因为动作本身可以是嵌套的决策

Pyparsing具有内置支持,可以简化算术和布尔表达式的定义,包括操作的优先级、括号中的分组以及递归表达式。下面是不同部分的pyparsing语法。首先,这里是一些基本的解析元素:

LPAR,RPAR = map(Suppress,"()")
# old pyparsing way
number = Regex(r"[+-]?\d+(\.\d*)?").setParseAction(lambda tokens:float(tokens[0]))
# new pyparsing way - parses many numeric formats, and uses a parse action
# to convert to float
number = pyparsing_common.fnumber()
varname = Word(alphas+'_', alphanums+'_')
附加到数字表达式的解析操作将在解析时自动将解析的数字转换为浮点值。Word类包含两个字符串:一个包含所有有效前导字符的字符串,以及一个包含所有有效正文字符的字符串。这个varname定义支持类似于Python标识符的变量名

Pyparsing具有
infixNotation
方法,该方法采用一个表达式作为基本操作数定义,并具有一个元组列表来定义每一级运算符:运算符表达式、整数(无论运算符是一元、二元或三元的,还是左关联或右关联的)
infixNotation
处理嵌套在括号中的算术表达式的递归定义。此表达式定义了基本的4函数数学:

operand = number | varname
arithExpr = infixNotation(operand,
    [
    (oneOf("+ -"), 1, opAssoc.RIGHT),
    (oneOf("* /"), 2, opAssoc.LEFT),
    (oneOf("+ -"), 2, opAssoc.LEFT),
    ])
下面是布尔条件的定义(我们最终将使用它来定义决策问题):

除了表达式定义之外,您还会注意到一些表达式后面还有一个带引号的字符串,就好像该表达式是一个使用该字符串调用的函数一样。事实上,这个“调用”实际上返回表达式的一个副本,并且匹配的标记被标记为该名称。这些结果名称在解析后的时候非常有助于挑选单独的匹配元素(类似于正则表达式中的命名组)

最后,要将这些部分组合到您的决策表达式中,以下是问题和行动表达式:

IF = CaselessKeyword("IF")
question = LPAR + IF + Group(booleanExpr)("condition") + RPAR
action = LPAR + cmd + RPAR | Group(decision)
请注意,操作定义可以包括决策,但操作用于定义决策。为了打破这种鸡和蛋的依赖关系,我们在本节的开头定义了
decision
,但使用了pyparsing
Forward
类的占位符表达式:

decision = Forward()

然后在定义了
question
action
之后,我们使用“这种语法确实是pyparsing的目标。基本格式非常简单,在pyparsing中,它看起来像:

decision = '(' + '('+question+')' + '('+action+')' + '('+action+')' + ')'
但一旦你开始添加算术表达式、布尔运算以及对“and”和“or”运算符的支持,事情就会变得复杂起来。此外,这是一种递归语法,因为动作本身可以是嵌套的决策

Pyparsing具有内置支持,可以简化算术和布尔表达式的定义,包括操作的优先级、括号中的分组以及递归表达式。下面是不同部分的pyparsing语法。首先,这里是一些基本的解析元素:

LPAR,RPAR = map(Suppress,"()")
# old pyparsing way
number = Regex(r"[+-]?\d+(\.\d*)?").setParseAction(lambda tokens:float(tokens[0]))
# new pyparsing way - parses many numeric formats, and uses a parse action
# to convert to float
number = pyparsing_common.fnumber()
varname = Word(alphas+'_', alphanums+'_')
附加到数字表达式的解析操作将在解析时自动将解析的数字转换为浮点值。Word类包含两个字符串:一个包含所有有效前导字符的字符串,以及一个包含所有有效正文字符的字符串。这个varname定义支持类似于Python标识符的变量名

Pyparsing具有
infixNotation
方法,该方法采用一个表达式作为基本操作数定义,并具有一个元组列表来定义每一级运算符:运算符表达式、整数(无论运算符是一元、二元或三元的,还是左关联或右关联的)
infixNotation
处理嵌套在括号中的算术表达式的递归定义。此表达式定义了基本的4函数数学:

operand = number | varname
arithExpr = infixNotation(operand,
    [
    (oneOf("+ -"), 1, opAssoc.RIGHT),
    (oneOf("* /"), 2, opAssoc.LEFT),
    (oneOf("+ -"), 2, opAssoc.LEFT),
    ])
下面是布尔条件的定义(我们最终将使用它来定义决策问题):

除了表达式定义之外,您还会注意到一些表达式后面还有一个带引号的字符串,就好像该表达式是一个使用该字符串调用的函数一样。事实上,这个“调用”实际上返回表达式的一个副本,并且匹配的标记被标记为该名称。这些结果名称在解析后的时候非常有助于挑选单独的匹配元素(类似于正则表达式中的命名组)

最后,要将这些部分组合到您的决策表达式中,以下是问题和行动表达式:

IF = CaselessKeyword("IF")
question = LPAR + IF + Group(booleanExpr)("condition") + RPAR
action = LPAR + cmd + RPAR | Group(decision)
请注意,操作定义