这个计算器的目标是用PEMDAS来计算表达式(还没有括号,很快就会添加)。虽然这个程序有效,但我想用我用来攻击数学表达式的方法使它尽可能高效。
因此,我决定解决这个问题的方法是最初通过我的cleanUp()来组织表达式,这样以后操作/迭代就更容易了,例如:
"2+2 -4 * 1 / 3.344 - -2“变成了"2 + 2 - 4 * 1 / 3.344 + 2”,它现在可以很容易地被一个空间分割,计算过程现在要简单得多,但是我觉得我的cleanUp()函数可以更高效。(我还在学习Python 3内置函数的时间复杂性)
这是我的全部代码,可以随意评论程序的任何其他部分,但我主要要求对cleanUp()函数进行优化改进。
import time
def isNumber(s):
#s must be a non-empty string
#returns True if it's convertible to float, else False
if (len(s)==0 and not s =='') or not isinstance(s, str):
print("type mismatch error: isNumber")
return "type mismatch error: isNumber"
try:
s = float(s)
return True
except ValueError:
#print("type mismatch error: isNumber")
return False
def cleanUp(s):
priorSpace = True
inDecimal = False
ops = ["+","-","*","/","^"]
s = s.replace("+", " + ").replace("-", " - ").replace("*", " * ").replace("/", " / ").replace("^", " ^ ")
st = list(s)
for i,c in enumerate(s):
if (not isNumber(c) and c not in ops) and priorSpace:
if c == "." and not inDecimal:
inDecimal = True
elif c == "." and inDecimal:
st[i] = ""
else:
st[i] = ""
inDecimal = False
elif (not isNumber(c) and c not in ops) and not priorSpace:
if c == "." and not inDecimal:
inDecimal = True
elif c == "." and inDecimal:
st[i] = ""
else:
st[i] = " "
priorSpace = True
inDecimal = False
else:
priorSpace = False
final = ''.join(st).strip().split(' ')
if '-' in final[0]:
del final[0]
final[0] = '-' + final[0]
newNumber, newOpr, oprPos = getNextNumber(final, 0)
if oprPos == None:
return newNumber
cacheNum=newNumber
pos=oprPos+1 #the new current position
opr=newOpr
while pos<(len(final)-1):
newNumber, newOpr, oprPos = getNextNumber(final, pos)
if (newOpr == None):
break
if (not isNumber(newNumber) and newNumber == '-'):
del final[oprPos-1] #BOOKMARK
final[oprPos-1] = '-' + final[oprPos-1]
if (not isNumber(newNumber) and newNumber != '-'):
print("error at line AB", newNumber)
return "error at line AB"
pos=oprPos+1
return (final)
def getNextNumber(expr, pos):
#expr is a given arithmetic formula in string
temp = expr
#pos = start position in expr
#1st returned value = the next number (None if N/A)
#2nd returned value = the next operator (None if N/A)
#3rd retruned value = the next operator position (None if N/A)
ops = ["+","-","*","/"]
if len(expr)==0 or pos<0 or pos>=len(expr) or not isinstance(pos, int):
print("type mismatch error: getNextNumber")
return None, None, "type mismatch error: getNextNumber"
#--- function code starts ---#
res3 = 0
res2 = 0
if (pos+1) < len(temp):
res3 = pos+1
res2 = temp[pos+1]
else:
res3 = None
res2 = None
return ((temp[pos], res2, res3))
#--- function code ends ---#
def exeOpr(num1, opr, num2):
#This is a simple utility function skipping type check
if opr=="+":
return num1+num2
elif opr=="-":
return num1-num2
elif opr=="*":
return num1*num2
elif opr=="/":
return num1/num2
elif opr=="^":
return num1**num2
else:
return None
def calc(expr):
#expr: nonempty string that is an arithmetic expression
#the fuction returns the calculated result
expr = cleanUp(expr)
if len(expr)<=0:
print("argument error: line A in eval_expr") #Line A
return "argument error: line A in eval_expr"
#Hold two modes: "addition" and "multiplication"
#Initializtion: get the first number
newNumber, newOpr, oprPos = getNextNumber(expr, 0)
ops = ["^","*","/","+","-"]
if newNumber is None or not isNumber(newNumber):
print("input formula error: line B in eval_expr") #Line B
return "input formula error: line B in eval_expr"
elif newOpr is None or not newOpr in ops:
return newNumber
cacheNum=newNumber
pos=oprPos+1 #the new current position
opr=newOpr #the new current operator
#start the calculation. Use the above functions effectively.
new_expr = expr
while True:
newNumber, newOpr, oprPos = getNextNumber(new_expr, pos)
#print(cacheNum, opr, newNumber, "The next opr however is", newOpr)
if (not isNumber(newNumber)):
print("input formula error: line C in eval_expr") #Line C
return "input formula error: line C in eval_expr"
if (newOpr == None):
break
if(newOpr == "^"):
temp = getNextNumber(new_expr, oprPos+1)[0]
if (not isNumber(temp)):
print("input formula error: line D in eval_expr") #Line D
return "input formula error: line D in eval_expr"
#print("Weee", newOpr, newNumber, "with", temp)
subs = exeOpr(float(newNumber), newOpr, float(temp))
del new_expr[oprPos-1]
del new_expr[oprPos-1]
new_expr[oprPos-1] = str(subs)
#print("The new expression to start calculating is: " + new_expr)
elif((newOpr == "*" or newOpr == "/") and (opr not in ["^","*","/"])):
temp, temp_Opr, temp_Pos = getNextNumber(new_expr, oprPos+1)
#print("uhhh", temp_Opr)
if temp_Opr == "^":
temp2 = getNextNumber(new_expr, oprPos+3)[0]
if (not isNumber(temp)):
print("input formula error: line D in eval_expr") #Line D
return "input formula error: line D in eval_expr"
#print("We", temp_Opr, temp, "with", temp2)
subs = exeOpr(float(temp), temp_Opr, float(temp2))
del new_expr[temp_Pos-1]
del new_expr[temp_Pos-1]
new_expr[temp_Pos-1] = str(subs)
#print("The new expression to start calculating is: " + new_expr)
else:
if (not isNumber(temp)):
print("input formula error: line D in eval_expr") #Line D
return "input formula error: line D in eval_expr"
#print("Weee", newOpr, newNumber, "with", temp)
subs = exeOpr(float(newNumber), newOpr, float(temp))
del new_expr[oprPos-1]
del new_expr[oprPos-1]
new_expr[oprPos-1] = str(subs)
#print("The new expression to start calculating is: " + new_expr)
elif((newOpr == "+" or newOpr == "-") and opr not in ["+","-"]):
subs = exeOpr(float(cacheNum), opr, float(newNumber))
del new_expr[pos-2]
del new_expr[pos-2]
new_expr[pos-2] = str(subs)
cacheNum=str(subs)
opr=newOpr
#print("The new expressionn to start calculating is: " + new_expr)
else:
subs = exeOpr(float(cacheNum), opr, float(newNumber))
del new_expr[pos-2]
del new_expr[pos-2]
new_expr[pos-2] = str(subs)
#print("The new expression to start calculating is: " + new_expr)
cacheNum=str(subs)
opr=newOpr
subs = exeOpr(float(cacheNum), opr, float(newNumber))
#print(new_expr)
del new_expr[new_expr.index(cacheNum)]
del new_expr[new_expr.index(opr)]
new_expr[new_expr.index(newNumber)] = str(subs)
return float(new_expr[0])
print(calc("2+2 -4 * 1 / 3.344 - -2")发布于 2017-09-28 08:18:00
可以用几乎一个正则表达式更改整个cleanUp方法
举个例子:
import re
def clean(s):
return re.split("([+\-\/*])", s.replace(" ", ""))
>>> print(clean("2+2 -4 * 1 / 3.344 - -2"))
>>> ['2', '+', '2', '-', '4', '*', '1', '/', '3.344', '-', '', '-', '2']这几乎与您的输出只有不同之处相同,当有两个操作器时,它会添加一个空的''。
这可以使用一些列表切片来修复,使干净的看起来如下所示:
import re
def clean(s):
cleaned_expr = re.split("([+\-\/*])", s.replace(" ", ""))
while '' in cleaned_expr:
# Remove empty and concat operator to next number
i = cleaned_expr.index('')
cleaned_expr[i] = cleaned_expr[i+1] + cleaned_expr[i+2]
del cleaned_expr[i+1:i+3]
return cleaned_expr
>>> print(clean("2+2 -4 * 1 / 3.344 - -2"))
>>> ['2', '+', '2', '-', '4', '*', '1', '/', '3.344', '-', '-2']
>>> print(clean("2+2- -4 * 1 / 3.344 -2"))
>>> ['2', '+', '2', '-', '-4', '*', '1', '/', '3.344', '-', '2']其他一些轻微的PEP8改进包括:
clean_up()而不是cleanUp=这样的运算符周围的空白,周围的空白回想起来,感谢@Mathias,您的calc()感到有问题,作为一个诚实的审阅者,我建议它处理像这个['2', '+', '2', '-', '4', '*', '1', '/', '3.344', '-', '-', '2']那样的输入,当它被修复时,我想再看看它,因为现在它感觉太错误了。
# The cleanest clean (but incorrect output for your calc)
import re
def clean(s):
s = re.split("([+\-\/*])", s.replace(" ", ""))
return [token for token in s if token]
>>> print(clean("2+2 -4 * 1 / 3.344 - -2"))
>>> ['2', '+', '2', '-', '4', '*', '1', '/', '3.344', '-', '-', '2']发布于 2017-09-27 11:22:20
不管事实如何,您的代码在返回时没有正常运行。
input formula error: line C in eval_expr
input formula error: line C in eval_expr使用示例输入,我建议将模块简化为
from re import compile
ARITHMETIC_EXPRESSIONS = compile('[0-9]*( ){0,}([+-/*^]( ){0,}[0-9]*( ){0,})*')
LEADING_ZEROS = compile('^0+(?=.)')
def coerce_python_syntax(string):
"""Converts arithmetic expression to python syntax."""
string = string.replace('^', '**')
return LEADING_ZEROS.sub('', string)
def calc(string):
"""Calculates the arithmetic expression given by string."""
if ARITHMETIC_EXPRESSIONS.fullmatch(string):
return eval(coerce_python_syntax(string))
raise ValueError('String is not a safe arithmetic expression.')
if __name__ == '__main__':
print(calc("2+2 -4 * 1 / 3.344 - -2"))因为您正在实现基本的算术计算,python已经很冷了。
https://codereview.stackexchange.com/questions/176587
复制相似问题