Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 通过匹配括号计算字符串_Python_Parentheses_Pyparsing - Fatal编程技术网

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])