猿问

如何将字符串分解为嵌套令牌?

我有由布尔项和方程组成的字符串,如下所示

x=1 AND (x=2 OR x=3) AND NOT (x=4 AND x=5) AND (x=5) AND y=1

我想将 它们分成由 分隔的组,同时将括号作为分组运算符。例如,上面字符串的结果将是xAND

[['x=1'], ['x=2', 'x=3'], ['x=4'], ['x=5'], ['x=5']]

x=2并且位于同一组中,因为它们由 分组,而不是由 分隔。最后一个等式被忽略,因为它不以 开头。x=3()ANDx

更新

另一个例子是

x=1 AND (x=2 OR (x=3 AND x=4))

其中每个等式应该是分开的

[['x=1'], ['x=2', [['x=3'], ['x=4']]]

我发现最接近的是这篇文章,但我不知道如何根据我的需求修改它。


慕斯王
浏览 88回答 2
2回答

BIG阳

正如您可能在另一个问题中看到的那样,解析诸如此类的中缀表示法最好使用帮助程序(以前称为 )进行解析。以下是用于您的问题的基础知识:infixNotationoperatorPrecedenceinfixNotationimport pyparsing as pp# define expressions for boolean operator keywords, and for an ident# (which we take care not to parse an operator as an identifier)AND, OR, NOT = map(pp.Keyword, "AND OR NOT".split())any_keyword = AND | OR | NOTident = pp.ungroup(~any_keyword + pp.Char(pp.alphas))ident.setName("ident")# use pyparsing_common.number pre-defined expression for any numeric valuenumeric_value = pp.pyparsing_common.number# define an expression for 'x=1', 'y!=200', etc.comparison_op = pp.oneOf("= != < > <= >=")comparison = pp.Group(ident + comparison_op + numeric_value)comparison.setName("comparison")# define classes for the parsed results, where we can do further processing by# node type laterclass Node:&nbsp; &nbsp; oper = None&nbsp; &nbsp; def __init__(self, tokens):&nbsp; &nbsp; &nbsp; &nbsp; self.tokens = tokens[0]&nbsp; &nbsp; def __repr__(self):&nbsp; &nbsp; &nbsp; &nbsp; return "{}:{!r}".format(self.oper, self.tokens.asList())class UnaryNode(Node):&nbsp; &nbsp; def __init__(self, tokens):&nbsp; &nbsp; &nbsp; &nbsp; super().__init__(tokens)&nbsp; &nbsp; &nbsp; &nbsp; del self.tokens[0]class BinaryNode(Node):&nbsp; &nbsp; def __init__(self, tokens):&nbsp; &nbsp; &nbsp; &nbsp; super().__init__(tokens)&nbsp; &nbsp; &nbsp; &nbsp; del self.tokens[1::2]class NotNode(UnaryNode):&nbsp; &nbsp; oper = "NOT"class AndNode(BinaryNode):&nbsp; &nbsp; oper = "AND"class OrNode(BinaryNode):&nbsp; &nbsp; oper = "OR"# use infixNotation helper to define recursive expression parser,# including handling of nesting in parenthesesexpr = pp.infixNotation(comparison,&nbsp; &nbsp; &nbsp; &nbsp; [&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (NOT, 1, pp.opAssoc.RIGHT, NotNode),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (AND, 2, pp.opAssoc.LEFT, AndNode),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (OR, 2, pp.opAssoc.LEFT, OrNode),&nbsp; &nbsp; &nbsp; &nbsp; ])现在尝试在测试字符串上使用此解析器。exprtest = "x=1 AND (x=2 OR x=3 OR y=12) AND NOT (x=4 AND x=5) AND (x=6) AND y=7"try:&nbsp; &nbsp; result = expr.parseString(test, parseAll=True)&nbsp; &nbsp; print(test)&nbsp; &nbsp; print(result)except pp.ParseException as pe:&nbsp; &nbsp; print(pp.ParseException.explain(pe))给:x=1 AND (x=2 OR x=3 OR y=12) AND NOT (x=4 AND x=5) AND (x=6) AND y=7[AND:[['x', '=', 1], OR:[['x', '=', 2], ['x', '=', 3], ['y', '=', 12]], NOT:[AND:[['x', '=', 4], ['x', '=', 5]]], ['x', '=', 6], ['y', '=', 7]]]从这一点开始,折叠嵌套的 AND 节点并删除非比较可以使用常规 Python 完成。x

慕雪6442864

我想你可以做这样的事情:operators = ["AND NOT", "AND"]sepChar = ":"yourInputString = yourInputString.replace("(","").replace(")","") # remove the parenthesis# Replace your operators with the separator characterfor op in operators:&nbsp; &nbsp; yourInputString = yourInputString.replace(op,sepChar)# output of your string so far# yourInputString# 'x=1 : x=2 OR x=3 : x=4 : x=5 : x=5 : y=1'# Create a list with the separator characteroperationsList = youtInputString.split(sepChar)&nbsp;# operationsList# ['x=1', 'x=2 OR x=3', 'x=4', 'x=5', 'x=5', 'y=1']# For the second result, let's do another operation list:operators2 = ["OR"]output = []# Loop to find the other operatorsfor op in operationsList:&nbsp; &nbsp; for operator in operators2:&nbsp; &nbsp; &nbsp; &nbsp; if operator in op:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; op = op.split(operator)&nbsp; &nbsp; output.append(op)# output:# [['x=1'], ['x=2', 'x=3'], ['x=4'], ['x=5'], ['x=5'],['y=1']]&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;在这种情况下,我使用“:”作为分隔字符,但您可以根据需要进行更改。如果有帮助,请让我知道!编辑对于括号嵌套方法,我带来了一些精彩的东西:import reoperators = ["AND NOT","AND","OR"]# Substitute parenthesisyourInputString = yourInputString.replace("(","[").replace(")","]")# yourInputString# "[x=1 AND [x=2 OR x=3] AND NOT [x=4 AND x=5] AND [x=5] AND y=1]"# Replace your operatorsfor op in operators:&nbsp; &nbsp; yourInputString = yourInputString(op,",")# yourInputString# "[x=1 , [x=2 , x=3] , [x=4 , x=5] , [x=5] , y=1]"# Find matches like x = 5 and substitue with 'x = 5'compiler = re.compile(r"[xyz]{1}=\d")matches = compiler.findall(yourInputString)# matches# ['x=1', 'x=2', 'x=3', 'x=4', 'x=5', 'x=5', 'y=1']# Convert the list into unique outputsmatches = list(set(matches))# matches# ['x=1', 'x=2', 'x=3', 'x=4', 'x=5', 'y=1']# Replace your matches to add quotes to each elementfor match in matches:&nbsp; &nbsp; yourInputString = yourInputString.replace(match,f"'{match}'")# yourInputString# "['x=1' , ['x=2' , 'x=3'] , ['x=4' , 'x=5'] , ['x=5'] , 'y=1']"# Here is the special move, convert your text into listmyList = eval(yourInputString)# myList# ['x=1', ['x=2', 'x=3'], ['x=4', 'x=5'], ['x=5'], 'y=1']
随时随地看视频慕课网APP

相关分类

Python
我要回答