Python 通过匹配括号计算字符串
以编程方式翻译字符串的最佳方法是什么Python 通过匹配括号计算字符串,python,parentheses,pyparsing,Python,Parentheses,Pyparsing,以编程方式翻译字符串的最佳方法是什么 "((abc&(def|ghi))|jkl)&mno" 按以下方式执行: if ((func('abc') and (func('def') or func('ghi'))) or func('jkl')) and func('mno'): return True 我觉得必须有一个简单的方法来实现这一点,但我无法控制它。如果字符串不比显示的复杂(例如,仅由这些符号加上字母/数字组成),您可以根据需要使用一些简单
"((abc&(def|ghi))|jkl)&mno"
按以下方式执行:
if ((func('abc') and (func('def') or func('ghi'))) or func('jkl')) and func('mno'):
return True
我觉得必须有一个简单的方法来实现这一点,但我无法控制它。如果字符串不比显示的复杂(例如,仅由这些符号加上字母/数字组成),您可以根据需要使用一些简单的正则表达式替换匹配项来解析它。之后,您可以使用
eval()
将其作为python代码运行
例如:
重新导入
def func(x):
#只是一个例子。。。
返回真值
s=“((abc和(def | ghi))| jkl)和mno”
s=re.sub(r'(\w+),r“func('\1')”,s)
s=s.replace(“&”、“and”)
s=s.replace(“|”、“或”)
印刷品
打印(评估)
输出:
((func('abc')和(func('def')或func('ghi'))或func('jkl'))和func('mno'))
真的
这是一个有趣的小问题,解决方案有很多层
首先,给出这个示例,您需要一个基本的中缀符号解析器。在pyparsing中,有一个内置的助手方法infixNotation
。几个pyparsing示例展示了如何使用infixNotation
解析布尔表达式。下面是一个将解析示例表达式的解析器:
import pyparsing as pp
term = pp.Word(pp.alphas)
AND = pp.Literal("&")
OR = pp.Literal("|")
expr = pp.infixNotation(term,
[
(AND, 2, pp.opAssoc.LEFT,),
(OR, 2, pp.opAssoc.LEFT,),
])
print(expr.parseString(sample).asList())
对于您的样本,这将打印:
[[[['abc', '&', ['def', '|', 'ghi']], '|', 'jkl'], '&', 'mno']]
您可以看到,我们不仅捕获了表达式,还捕获了括号中的分组
我们可以通过添加解析操作开始转换到所需的输出。这些是pyparsing将调用的解析时回调,用不同的值(不需要是字符串,可以是用于求值的AST节点,但在本例中,我们将返回一个修改后的字符串)替换解析后的令牌
解析操作可以是具有各种签名的方法:
function()
function(tokens)
function(location, tokens)
function(input_string, location, tokens)
对于AND和OR,我们只需要用相应的“AND”和“AND”或“OR”关键字替换解析后的运算符。对于已解析的变量项,我们希望将“xxx”更改为“func(xxx)”,因此我们编写一个解析操作,该操作接受已解析的标记,并返回修改后的字符串
AND.addParseAction(lambda: " and ")
OR.addParseAction(lambda: " or ")
term.addParseAction(lambda t: "func('{}')".format(t[0]))
expr.addParseAction(lambda t: "({})".format(''.join(t[0])))
expr
的解析操作很有趣,因为它所做的只是获取解析的内容,使用'.join()
,然后将其包装在()
中。由于expr
实际上是一个递归表达式,我们将看到它在解析的嵌套列表中的每一级都正确地包装成()
添加这些解析操作后,我们可以再次尝试调用parseString()
,现在给出:
["(((func('abc') and (func('def') or func('ghi'))) or func('jkl')) and func('mno'))"]
接近
要将格式设置为所需的if
语句,我们可以使用另一个解析操作。但是我们不能将此解析操作直接附加到expr
,因为我们看到expr
(及其关联的解析操作)将在所有嵌套级别上解析。因此,我们可以创建expr的“外部”版本,即expr的容器表达式:
outer_expr = pp.Group(expr)
解析操作与我们在expr
中看到的类似,我们使用输入标记返回一个新字符串:
def format_expression(tokens):
return "if {}:\n return True".format(''.join(tokens[0]))
outer_expr.addParseAction(format_expression)
现在我们使用outer_expr
解析输入字符串:
print(outer_expr.parseString(sample)[0])
获取:
if (((func('abc') and (func('def') or func('ghi'))) or func('jkl')) and func('mno')):
return True
(此值上可能有一组额外的(),如果需要,可以在outer_expr
的解析操作中删除它们。)
解析器的完成版本(取消对中间print语句的注释以查看解析器功能的进展):
这只解决了部分问题,因为它没有考虑字符串中的“&”和“|”。StackOverflow不是代码编写服务。请编辑您的代码,尝试在您的问题中解决此问题。如果我知道如何解决此问题,我将不会首先问此问题。链接线程没有改变这一点,因为它只占问题的一小部分。我说“尝试”-您应该表现出诚实的解决问题的尝试。阅读我不认为“尝试”有助于解决这个问题,当我在为一个复杂的问题寻求最佳实践解决方案时(由@PaulMcG提供,谢谢!),这个问题需要大量的知识和经验以及非常具体的技术。这正是stackoverflow的用途。这确实解决了问题。然而,这种解决方案在输入字符串格式错误的情况下似乎非常容易出错,使用eval()通常被认为是错误的做法(),因此我认为应该有更好的解决方案来解决这个问题。@JulianFreyberg使用
eval()
是错误的做法,只有当您不知道自己在做什么,并且在用户输入时使用它。该函数存在的原因是:要使用。当然,正确的方法是编写递归解析器,但这将比这个简单且快速编写的解决方案复杂得多,这就是为什么我在代码之前添加了“免责声明”。我完全同意你的观点,并将在我的情况下使用你的解决方案,因此我接受了你的答案。我只是想指出,可能存在更多的故障保护解决方案,在其他情况下可能更合适。
sample = "((abc&(def|ghi))|jkl)&mno"
import pyparsing as pp
term = pp.Word(pp.alphas)
AND = pp.Literal("&")
OR = pp.Literal("|")
expr = pp.infixNotation(term,
[
(AND, 2, pp.opAssoc.LEFT,),
(OR, 2, pp.opAssoc.LEFT,),
])
# print(expr.parseString(sample).asList())
AND.addParseAction(lambda: " and ")
OR.addParseAction(lambda: " or ")
term.addParseAction(lambda t: "func('{}')".format(t[0]))
expr.addParseAction(lambda t: "({})".format(''.join(t[0])))
# print(expr.parseString(sample).asList())
def format_expression(tokens):
return "if {}:\n return True".format(''.join(tokens[0]))
outer_expr = pp.Group(expr).addParseAction(format_expression)
print(outer_expr.parseString(sample)[0])