Edw*_*win 8 python parsing algebra
我目前正在从Java过渡到Python,并且已经承担了尝试创建一个计算器的任务,该计算器可以对基于中缀的数学表达式执行符号操作(不使用像Sympy这样的自定义模块).目前,它构建为接受空格分隔的字符串,并且只能执行(,),+, - ,*和/运算符.不幸的是,我无法弄清楚简化符号表达式的基本算法.
例如,给定字符串'2*((9/6)+ 6*x)',我的程序应执行以下步骤:
但是在分发2时我无法让程序忽略x.此外,如何处理'x*6/x'以便在简化后返回'6'?
编辑:澄清,通过"符号"我的意思是它将在输出中留下像"A"和"f"这样的字母,同时执行剩余的计算.
编辑2:我(大部分)完成了代码.如果有人在将来偶然发现这篇文章,或者你们中的任何一个人好奇,我会在这里发帖.
def reduceExpr(useArray):
# Use Python's native eval() to compute if no letters are detected.
if (not hasLetters(useArray)):
return [calculate(useArray)] # Different from eval() because it returns string version of result
# Base case. Returns useArray if the list size is 1 (i.e., it contains one string).
if (len(useArray) == 1):
return useArray
# Base case. Returns the space-joined elements of useArray as a list with one string.
if (len(useArray) == 3):
return [' '.join(useArray)]
# Checks to see if parentheses are present in the expression & sets.
# Counts number of parentheses & keeps track of first ( found.
parentheses = 0
leftIdx = -1
# This try/except block is essentially an if/else block. Since useArray.index('(') triggers a KeyError
# if it can't find '(' in useArray, the next line is not carried out, and parentheses is not incremented.
try:
leftIdx = useArray.index('(')
parentheses += 1
except Exception:
pass
# If a KeyError was returned, leftIdx = -1 and rightIdx = parentheses = 0.
rightIdx = leftIdx + 1
while (parentheses > 0):
if (useArray[rightIdx] == '('):
parentheses += 1
elif (useArray[rightIdx] == ')'):
parentheses -= 1
rightIdx += 1
# Provided parentheses pair isn't empty, runs contents through again; else, removes the parentheses
if (leftIdx > -1 and rightIdx - leftIdx > 2):
return reduceExpr(useArray[:leftIdx] + [' '.join(['(',reduceExpr(useArray[leftIdx+1:rightIdx-1])[0],')'])] + useArray[rightIdx:])
elif (leftIdx > -1):
return reduceExpr(useArray[:leftIdx] + useArray[rightIdx:])
# If operator is + or -, hold the first two elements and process the rest of the list first
if isAddSub(useArray[1]):
return reduceExpr(useArray[:2] + reduceExpr(useArray[2:]))
# Else, if operator is * or /, process the first 3 elements first, then the rest of the list
elif isMultDiv(useArray[1]):
return reduceExpr(reduceExpr(useArray[:3]) + useArray[3:])
# Just placed this so the compiler wouldn't complain that the function had no return (since this was called by yet another function).
return None
Run Code Online (Sandbox Code Playgroud)
在对符号进行操作之前,您需要进行更多处理。您想要获得的形式是叶节点中具有值的操作树。首先,您需要在字符串上运行词法分析器来获取元素 - 尽管如果您总是有空格分隔的元素,那么只需拆分字符串就足够了。然后,您需要使用所需的语法来解析该标记数组。
如果您需要有关语法和解析文本的理论信息,请从这里开始: http: //en.wikipedia.org/wiki/Parsing如果您需要更实用的内容,请访问https://github.com/pyparsing/pyparsing(您不需要不必使用 pyparsing 模块本身,但他们的文档有很多有趣的信息)或http://www.nltk.org/book
从2 * ( ( 9 / 6 ) + 6 * x ),您需要到达这样的树:
*
2 +
/ *
9 6 6 x
Run Code Online (Sandbox Code Playgroud)
然后您可以访问每个节点并决定是否要简化它。常量操作将是最简单的消除操作 - 只需计算结果并将“/”节点与 1.5 交换,因为所有子节点都是常量。
有很多策略可以继续,但本质上您需要找到一种方法来遍历树并对其进行修改,直到没有任何内容可以更改为止。
如果您想打印结果,只需再次遍历树并生成描述它的表达式即可。