在中缀到前缀转换期间处理指数

时间:2016-03-08 04:51:22

标签: python

我正在尝试将某些内容从中缀转换为前缀表示法。例如,我想要

A1 + B1 

看起来像:

add A1 B1

我有这段代码:

class Type(Enum):  # This could also be done with individual classes
    leftparentheses = 0
    rightparentheses = 1
    operator = 2
    empty = 3
    operand = 4
    negOperator = 5
    comma = 6
    exp = 7

OPERATORS = {  # get your data out of your code...
    "+": "add",
    "-": "subtract",
    "*": "multiply",
    "%": "modulus",
    "/": "safeDiv",
}

def textOperator(string):
    if string not in OPERATORS:
        sys.exit("Unknown operator: " + string)
    return OPERATORS[string]

def typeof(string):
    if string == '(':
        return Type.leftparentheses
    elif string == ')':
        return Type.rightparentheses
    elif string == ',':
        return Type.comma
    elif string == '^':
        return Type.exp
    elif string in OPERATORS:
        return Type.operator
    elif string == ' ':
        return Type.empty
    else:
        return Type.operand

def process(tokens):

    stack = []
    previousTokenCategory = Type.leftparentheses

    while tokens:
        token = tokens.pop()

        category = typeof(token)

#ignore negative signs from negative numbers
        if previousTokenCategory == Type.leftparentheses or previousTokenCategory == Type.operator:
            if token == "-":
                category = Type.operand

        #print("token = ", token, " (" + str(category) + ")")

        if category == Type.operand:
            stack.append(token)
            temp = ''.join(stack)
            while len(stack) > 0 :
                stack.pop()
            stack.append(temp)
            previousTokenCategory = Type.operand
        elif category == Type.operator:
            stack.append((textOperator(token), stack.pop(), process(tokens)))
            previousTokenCategory = Type.operator
        elif category == Type.exp:
            stack.append(("exp", stack.pop(), process(tokens)))
            previousTokenCategory = Type.exp
        elif category == Type.leftparentheses:
            stack.append(process(tokens))
            previousTokenCategory = Type.leftparentheses
        elif category == Type.rightparentheses:
            previousTokenCategory = Type.rightparentheses
            return stack.pop()
        elif category == Type.empty:
            continue

    return stack.pop()

INFIX = "(1 + ((C24 + A2) * (B2 - F4))"
postfix = process(list(INFIX[::-1]))

当我没有指数时,这很有用。例如“(1 +((C24 + A2)*(B2 - F4))”转换为:

('add', '1', ('multiply', ('add', 'C24', 'A2'), ('subtract', 'B2', 'F4')))

但是当我有指数时,它不起作用。例如,当我有这个:“(1 +((C24 + A2)^ 2 *(B2 - F4))”它将它转换为:

('add', '1', ('exp', ('add', 'C24', 'A2'), ('multiply', '2', ('subtract', 'B2', 'F4'))))

即使正确的输出应该是这样的:

('add', '1', ('multiply', ('exp', ('add', 'C24', 'A2'), 2), ('subtract', 'B2', 'F4')))

我做错了什么?

1 个答案:

答案 0 :(得分:0)

  1. 使用tokens.pop(0),首次调用流程时无需撤消列表。

  2. 尝试调试这样的状态机时,更改堆栈时打印或记录状态通常很有用:print(stack [-3:],category,tokens [:3])。< / p>

  3. 正如BrenBarn评论的那样,你的函数并没有考虑'^'和'''之前出现的概念,它出现在'+'和' - '之前,等等。运算符优先级。在您的函数中,stack.append(("exp", stack.pop(), process(tokens)))会导致^之后的所有内容都被处理为指数。

  4. 解决这个问题的一种方法是使用2个堆栈:运算符堆栈和操作数堆栈。

    For each token
        If its an operand, push it on the operand stack
        If its an operator, compare it with the operator on the top of the operator stack
            If the operator on the stack has lower precedence, then
                push the new operator on the stack
            If the operator on the stack has higher or equal precedence, then 
                pop the operator and its operands off the stacks
                apply the operator to the operands, and
                push the result back on the operand stack
                push the new operator on the operator stack
        If it's a '(' push it on the operator stack
        If it's a ')' pop and apply operators to operands until a '(' is on 
            the top of the operator stack, then pop the '('.
        If its the end of the input, apply the operators to the operands.  At the 
            end, the operand stack should be empty and the operand stack should
            just have the final result on it.
    

    示例:“1 +(C24 + A2)^ 2 *(B2-F4)”

    在处理第一个')'之前,堆栈看起来像:

    operators = ['+', '(', '+']
    operands = ['1', 'C24', 'A2']
    token = ')'
    

    '+'高于')',因此将'+'应用于操作数堆栈的顶部以获取:

    operators = ['+', '(']
    operands = ['1', ('add', 'C24', 'A2')]
    token = ')'
    

    令牌是')',运算符堆栈的顶部是')',所以弹出'(',然后获取下一个令牌。

    operators = ['+']
    operands = ['1', ('add', 'C24', 'A2')]
    token = '^'
    

    '+'的优先级低于'^',因此在堆栈上按'^'。 '2'将被推到操作数堆栈上。

    operators = ['+', '^']
    operands = ['1', ('add', 'C24', 'A2'), '2']
    token = '*'
    

    现在'^'的优先级高于'*',因此将其应用于堆栈以获取:

    operators = ['+']
    operands = ['1', ('exp', ('add', 'C24', 'A2'), '2')]
    token = '('
    

    等等