O seguinte trecho de código obtém uma string infix e irá convertê-lo para outfix e saída que nova expressão como uma string. No entanto ele não suporta números negativos ou carros alegóricos. O código a seguir permite apenas para valores de um dígito:
Tais como (0-9) nada como 10 ou 11. Caso contrário, ele lança um "erro fundamental" . Além disso, se eu adicionar um sinal negativo também lança um erro de chave.
class Stack:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
return self.items[len(self.items)-1]
def size(self):
return len(self.items)
def isNumber(self, txt):
if not isinstance(txt,str) or len(txt.strip())==0:
print("Argument error in isNumber")
return False
# YOUR CODE STARTS HERE
try:
float(txt)
return True
except ValueError:
return False
#########################################################################################################
def infixToPostfix(infixexpr):
prec = {}
prec["^"] = 4
prec["*"] = 3
prec["/"] = 3
prec["+"] = 2
prec["-"] = 2
prec["("] = 1
opStack = Stack()
postfixList = []
tokenList = infixexpr.split()
for token in tokenList:
if token in "0123456789":
postfixList.append(token)
elif token == '(':
opStack.push(token)
elif token == ')':
topToken = opStack.pop()
while topToken != '(':
postfixList.append(topToken)
topToken = opStack.pop()
else:
while (not opStack.isEmpty()) and \
(prec[opStack.peek()] >= prec[token]):
postfixList.append(opStack.pop())
opStack.push(token)
while not opStack.isEmpty():
postfixList.append(opStack.pop())
return " ".join(postfixList)
Então aqui está a minha correção para permitir que carros alegóricos, bem como:
Eu adicionei esta função:
def isNumber(x):
try:
float(x)
return True
except ValueError:
return False
E mudou esta linha: if token in "0123456789":
para isso:if Stack.isNumber(token):
E agora o código permite que carros alegóricos.
Então, qual é o outro problema? Bem, o outro problema é que meu código assume a seqüência de entrada vai ter exatamente um espaço entre cada um dos personagens, daí eu string.split () para colocar todos os personagens na lista. Exceto a seqüência de entrada pode ter uma quantidade arbitrária de espaços entre os caracteres, e se não há espaços, o meu código irá comparar algo como "((" a minha lista de caracteres e não encontrá-lo e lançar um erro Key . Então, já que Eu tenho que permitir que um número negativo (observado por um sinal de menos). Como posso modificar meu código para que ele não vai mais jogar a keyerror
e me permite ter números negativos?
Quando eu fizer isso:
print(Stack.infixToPostfix("( ( 1 + 3 ) ) * 4 - ( 9.2 - 0 ) * ( 5 + 8 )"))
Meu código gera o seguinte: 1 3 + 4 * 9.2 0 - 5 8 + * -
Que funciona perfeitamente, no entanto se eu remover um espaço:
"(( 1 + 3 ) ) * 4 - ( 9.2 - 0 ) * ( 5 + 8 )"
Meu código não funciona mais. Erro Key '((' Eu sei porque ele lança este erro (explicação acima), mas eu não tenho certeza de como corrigi-lo.
Então TL pergunta final: DR
Como modificar meu código infixtopostfix para permitir uma quantidade arbitrária de espaços entre os caracteres e permitir números negativos?
Primeiro crie uma função separada que irá produzir uma lista de tokens de sua corda. Um token é o número (sem sinal) ou um único caractere:
def tokenize(s):
s = re.sub(r"\s+", "", s)
result = []
while (s):
if s[0] in "0123456789":
number = s[0]
s = s[1:]
while (s and s[0] in "0123456789."):
number += s[0]
s = s[1:]
result.append(number)
if s:
result.append(s[0])
s = s[1:]
else:
result.append(s[0])
s = s[1:]
return result
Em seguida, você precisa manter o controle das operações unárias mais e menos. Para fazer isso, apresentamos um especial 'neg' operação - quando você processar esta operação no postfix notação que você acabou de negar o valor no topo da pilha operando.
Você espera unárias mais e menos operações no início da string ou logo após a abertura '('. Depois de processar um número operando ou um fechamento ')' você redefinir o sinalizador unário para Falso, porque unário mais ou menos não pode aparecer em estas posições. Quando a bandeira unário é verdade que você deve manter rastreamento de entrada '+' e '-', utilize boolean flag 'neg' para ele. 'Neg' mudança de estado em cada '-'. Quando você finalmente encontrar um operando - verificar o estado de bandeira 'neg'. Se isso for verdade, então você precisa colocar a nossa operação especial 'neg' após o operando. Colocar uma operação 'neg' após o fechamento ')' é um pouco complicado e requer o uso de opStack.
def infixToPostfix(infixexpr):
prec = {}
prec["^"] = 3
prec["*"] = 3
prec["/"] = 3
prec["+"] = 2
prec["-"] = 2
prec["("] = 1
prec["neg"] = 1
opStack = Stack()
postfixList = []
tokenList = tokenize(infixexpr)
print(tokenList)
unary = True
neg = False
for token in tokenList:
if unary and token in "+-":
if token == '-':
neg = not neg
elif isNumber(token):
postfixList.append(token)
if neg:
postfixList.append("neg")
neg = False
unary = False
elif token == '(':
if neg:
opStack.push("neg")
neg = False
opStack.push(token)
unary = True
elif token == ')':
topToken = opStack.pop()
unary = False
while topToken != '(':
postfixList.append(topToken)
topToken = opStack.pop()
if not opStack.isEmpty() and opStack.peek() == "neg":
postfixList.append(opStack.pop())
else:
while (not opStack.isEmpty()) and \
(prec[opStack.peek()] >= prec[token]):
postfixList.append(opStack.pop())
opStack.push(token)
while not opStack.isEmpty():
postfixList.append(opStack.pop())
return " ".join(postfixList)
Entrada:
"-(( 1 + 3 ) ) * 4 - ( -9.2 - 0 ) * ( 5 + 8 ) - 4 * (-2)"
Resultado:
1 3 + neg 4 * 9.2 neg 0 - 5 8 + * - 4 2 neg * -
ATUALIZAR
Se você quiser números processo negativas como um único negativa operando e não como um operando positivo seguido por uma operação de 'neg', então você só precisa de uma pequena modificação do método infixToPostfix. Você só precisa modificar o elif isNumber(token)
ramo. Vou colocá-lo embora aqui completa:
def infixToPostfix(infixexpr):
prec = {}
prec["^"] = 3
prec["*"] = 3
prec["/"] = 3
prec["+"] = 2
prec["-"] = 2
prec["("] = 1
prec["neg"] = 1
opStack = Stack()
postfixList = []
tokenList = tokenize(infixexpr)
unary = True
neg = False
for token in tokenList:
if unary and token in "+-":
if token == '-':
neg = not neg
elif isNumber(token):
if neg:
postfixList.append("-" + token)
else:
postfixList.append(token)
neg = False
unary = False
elif token == '(':
if neg:
opStack.push("neg")
neg = False
opStack.push(token)
unary = True
elif token == ')':
topToken = opStack.pop()
unary = False
while topToken != '(':
postfixList.append(topToken)
topToken = opStack.pop()
if not opStack.isEmpty() and opStack.peek() == "neg":
postfixList.append(opStack.pop())
else:
while (not opStack.isEmpty()) and \
(prec[opStack.peek()] >= prec[token]):
postfixList.append(opStack.pop())
opStack.push(token)
while not opStack.isEmpty():
postfixList.append(opStack.pop())
return " ".join(postfixList)
Agora, a saída é
1 3 + neg 4 * -9.2 0 - 5 8 + * - 4 -2 * -