如何将字符串分解为嵌套的标记?
How can I break a string into nested tokens?
我有由布尔项和方程组成的字符串,就像这样
x=1 AND (x=2 OR x=3) AND NOT (x=4 AND x=5) AND (x=5) AND y=1
我想将 x
分成由 AND
分隔的组,同时将括号作为分组运算符。例如,上面字符串的结果将是
[['x=1'], ['x=2', 'x=3'], ['x=4'], ['x=5'], ['x=5']]
x=2
和 x=3
属于同一组,因为它们被 ()
分组并且没有被 AND
分隔。最后一个等式被忽略,因为它不是以 x
.
开头
更新
另一个例子是
x=1 AND (x=2 OR (x=3 AND x=4))
每个方程应该分开
[['x=1'], ['x=2', [['x=3'], ['x=4']]]
我找到的最接近的是这个 post 但我不知道如何修改它以满足我的需要。
我想你可以这样做:
operators = ["AND NOT", "AND"]
sepChar = ":"
yourInputString = yourInputString.replace("(","").replace(")","") # remove the parenthesis
# Replace your operators with the separator character
for op in operators:
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 character
operationsList = youtInputString.split(sepChar)
# 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 operators
for op in operationsList:
for operator in operators2:
if operator in op:
op = op.split(operator)
output.append(op)
# output:
# [['x=1'], ['x=2', 'x=3'], ['x=4'], ['x=5'], ['x=5'],['y=1']]
在本例中,我使用“:”作为分隔符,但您可以根据需要进行更改。如果这有帮助,请告诉我!
编辑
对于括号嵌套方法,我想出了一些绝妙的方法:
import re
operators = ["AND NOT","AND","OR"]
# Substitute parenthesis
yourInputString = 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 operators
for op in operators:
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 outputs
matches = list(set(matches))
# matches
# ['x=1', 'x=2', 'x=3', 'x=4', 'x=5', 'y=1']
# Replace your matches to add quotes to each element
for match in matches:
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 list
myList = eval(yourInputString)
# myList
# ['x=1', ['x=2', 'x=3'], ['x=4', 'x=5'], ['x=5'], 'y=1']
正如您可能在另一个问题中看到的那样,解析这样的中缀符号最好在 pyparsing 中使用 infixNotation
帮助程序(以前称为 operatorPrecedence
)完成。以下是使用 infixNotation
解决问题的基础知识:
import 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 | NOT
ident = pp.ungroup(~any_keyword + pp.Char(pp.alphas))
ident.setName("ident")
# use pyparsing_common.number pre-defined expression for any numeric value
numeric_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 later
class Node:
oper = None
def __init__(self, tokens):
self.tokens = tokens[0]
def __repr__(self):
return "{}:{!r}".format(self.oper, self.tokens.asList())
class UnaryNode(Node):
def __init__(self, tokens):
super().__init__(tokens)
del self.tokens[0]
class BinaryNode(Node):
def __init__(self, tokens):
super().__init__(tokens)
del self.tokens[1::2]
class NotNode(UnaryNode):
oper = "NOT"
class AndNode(BinaryNode):
oper = "AND"
class OrNode(BinaryNode):
oper = "OR"
# use infixNotation helper to define recursive expression parser,
# including handling of nesting in parentheses
expr = pp.infixNotation(comparison,
[
(NOT, 1, pp.opAssoc.RIGHT, NotNode),
(AND, 2, pp.opAssoc.LEFT, AndNode),
(OR, 2, pp.opAssoc.LEFT, OrNode),
])
现在尝试在测试字符串上使用此 expr
解析器。
test = "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:
result = expr.parseString(test, parseAll=True)
print(test)
print(result)
except pp.ParseException as pe:
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 节点并删除非 x
比较可以使用常规 Python.
完成
我有由布尔项和方程组成的字符串,就像这样
x=1 AND (x=2 OR x=3) AND NOT (x=4 AND x=5) AND (x=5) AND y=1
我想将 x
分成由 AND
分隔的组,同时将括号作为分组运算符。例如,上面字符串的结果将是
[['x=1'], ['x=2', 'x=3'], ['x=4'], ['x=5'], ['x=5']]
x=2
和 x=3
属于同一组,因为它们被 ()
分组并且没有被 AND
分隔。最后一个等式被忽略,因为它不是以 x
.
更新
另一个例子是
x=1 AND (x=2 OR (x=3 AND x=4))
每个方程应该分开
[['x=1'], ['x=2', [['x=3'], ['x=4']]]
我找到的最接近的是这个 post 但我不知道如何修改它以满足我的需要。
我想你可以这样做:
operators = ["AND NOT", "AND"]
sepChar = ":"
yourInputString = yourInputString.replace("(","").replace(")","") # remove the parenthesis
# Replace your operators with the separator character
for op in operators:
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 character
operationsList = youtInputString.split(sepChar)
# 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 operators
for op in operationsList:
for operator in operators2:
if operator in op:
op = op.split(operator)
output.append(op)
# output:
# [['x=1'], ['x=2', 'x=3'], ['x=4'], ['x=5'], ['x=5'],['y=1']]
在本例中,我使用“:”作为分隔符,但您可以根据需要进行更改。如果这有帮助,请告诉我!
编辑
对于括号嵌套方法,我想出了一些绝妙的方法:
import re
operators = ["AND NOT","AND","OR"]
# Substitute parenthesis
yourInputString = 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 operators
for op in operators:
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 outputs
matches = list(set(matches))
# matches
# ['x=1', 'x=2', 'x=3', 'x=4', 'x=5', 'y=1']
# Replace your matches to add quotes to each element
for match in matches:
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 list
myList = eval(yourInputString)
# myList
# ['x=1', ['x=2', 'x=3'], ['x=4', 'x=5'], ['x=5'], 'y=1']
正如您可能在另一个问题中看到的那样,解析这样的中缀符号最好在 pyparsing 中使用 infixNotation
帮助程序(以前称为 operatorPrecedence
)完成。以下是使用 infixNotation
解决问题的基础知识:
import 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 | NOT
ident = pp.ungroup(~any_keyword + pp.Char(pp.alphas))
ident.setName("ident")
# use pyparsing_common.number pre-defined expression for any numeric value
numeric_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 later
class Node:
oper = None
def __init__(self, tokens):
self.tokens = tokens[0]
def __repr__(self):
return "{}:{!r}".format(self.oper, self.tokens.asList())
class UnaryNode(Node):
def __init__(self, tokens):
super().__init__(tokens)
del self.tokens[0]
class BinaryNode(Node):
def __init__(self, tokens):
super().__init__(tokens)
del self.tokens[1::2]
class NotNode(UnaryNode):
oper = "NOT"
class AndNode(BinaryNode):
oper = "AND"
class OrNode(BinaryNode):
oper = "OR"
# use infixNotation helper to define recursive expression parser,
# including handling of nesting in parentheses
expr = pp.infixNotation(comparison,
[
(NOT, 1, pp.opAssoc.RIGHT, NotNode),
(AND, 2, pp.opAssoc.LEFT, AndNode),
(OR, 2, pp.opAssoc.LEFT, OrNode),
])
现在尝试在测试字符串上使用此 expr
解析器。
test = "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:
result = expr.parseString(test, parseAll=True)
print(test)
print(result)
except pp.ParseException as pe:
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 节点并删除非 x
比较可以使用常规 Python.