0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Pythonで中置記法を逆ポーランド記法に変換して計算する

Posted at

# 演算子のための定数
LEFT_ASSOC = 0
RIGHT_ASSOC = 1
 
# 対応する演算子
OPERATORS = {
    '+' : (0, LEFT_ASSOC),
    '-' : (0, LEFT_ASSOC),
    '*' : (5, LEFT_ASSOC),
    '/' : (5, LEFT_ASSOC),
    '%' : (5, LEFT_ASSOC),
    '^' : (10, RIGHT_ASSOC)
}
 
# 演算子かどうかの確認
def is_operator(token):
    return token in OPERATORS.keys()
 
# 結合性の確認
def is_associative(token, assoc):
    if not is_operator(token):
        raise ValueError('Invalid token: %s' % token)
    return OPERATORS[token][1] == assoc
 
# 二つの記号の優先順位を確認
def cmp_precedence(token1, token2):
    if not is_operator(token1) or not is_operator(token2):
        raise ValueError('Invalid tokens: %s %s' % (token1, token2))
    return OPERATORS[token1][0] - OPERATORS[token2][0]
 
# 中置記法を逆ポーランド記法に変換する
def infix_to_RPN(tokens):
    out = []
    stack = []
    for token in tokens:
        if is_operator(token):
            while len(stack) != 0 and is_operator(stack[-1]):
                if (is_associative(token, LEFT_ASSOC) and
                    cmp_precedence(token, stack[-1]) <= 0) or(
                    is_associative(token, RIGHT_ASSOC) and
                    cmp_precedence(token, stack[-1]) < 0):
                    out.append(stack.pop())
                    continue
                break
            stack.append(token)
        elif token == '(':
            stack.append(token)
        elif token == ')':
            while len(stack) != 0 and stack[-1] != '(':
                out.append(stack.pop())
            stack.pop()
        else:
            out.append(token)
    while len(stack) != 0:
        out.append(stack.pop())
    return out
 
# リストの要素をタブ区切りの文字列にする
def list_to_str_with_space(lst):
  str_w_space = '\t'.join([i for i in lst])
  return str_w_space

ops = {
  "+": (lambda a, b: a + b),
  "-": (lambda a, b: a - b),
  "*": (lambda a, b: a * b),
  "/": (lambda a, b: a / b),
  "^": (lambda a, b: a ** b)
}

# 逆ポーランド記法の数式を計算する
def calc_RPN(expression):
  tokens_RPN = expression.split()
  stack = []

  for token in tokens_RPN:
    if token in ops:
      arg2 = stack.pop()
      arg1 = stack.pop()
      result = ops[token](arg1, arg2)
      stack.append(result)
    else:
      stack.append(int(token))

  return stack.pop()

# 入力と出力のための関数
def in_and_out(input_equation):
    output = infix_to_RPN(input_equation.split(" "))
    stri = list_to_str_with_space(output)
    print(stri)
    result = calc_RPN(stri)
    print(result)

if __name__ == '__main__':
    in_and_out("( 1 + 2 ) * ( 3 / 4 ) ^ ( 5 + 6 )")
    in_and_out("( 2 + 3 ) * ( 4 / 5 ) ^ ( 6 + 7 )")
    in_and_out("( 7 + 6 ) * ( 5 / 4 ) ^ ( 3 + 2 )")

参考:
https://andreinc.net/2010/10/05/converting-infix-to-rpn-shunting-yard-algorithm/

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?