結果

問題 No.708 (+ー)の式
ユーザー Wataru MaedaWataru Maeda
提出日時 2018-10-24 23:03:19
言語 Python3
(3.11.6 + numpy 1.26.0 + scipy 1.11.3)
結果
AC  
実行時間 21 ms / 2,000 ms
コード長 5,706 bytes
コンパイル時間 124 ms
コンパイル使用メモリ 11,188 KB
実行使用メモリ 8,584 KB
最終ジャッジ日時 2023-08-12 07:02:17
合計ジャッジ時間 1,228 ms
ジャッジサーバーID
(参考情報)
judge14 / judge15
このコードへのチャレンジ(β)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 18 ms
8,352 KB
testcase_01 AC 19 ms
8,532 KB
testcase_02 AC 17 ms
8,076 KB
testcase_03 AC 17 ms
8,528 KB
testcase_04 AC 18 ms
8,492 KB
testcase_05 AC 17 ms
8,584 KB
testcase_06 AC 17 ms
8,420 KB
testcase_07 AC 17 ms
8,468 KB
testcase_08 AC 17 ms
8,464 KB
testcase_09 AC 18 ms
8,504 KB
testcase_10 AC 19 ms
8,444 KB
testcase_11 AC 19 ms
8,440 KB
testcase_12 AC 21 ms
8,508 KB
testcase_13 AC 19 ms
8,220 KB
testcase_14 AC 21 ms
8,528 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

import sys

# 演算子(ホントは二項演算子もクラス化したい)
class Operator:
    def __init__(self):
        self.name = ''
    def calc(self):
        pass
    def __str__(self):
        return self.name

# +演算子(二項演算子)
class PlusOperator(Operator):
    def __init__(self):
      self.name = '+'
    # 項を与えて演算を行う
    def calc(self, val1, val2):
      return val1.calc_value() + val2.calc_value()

# -演算子(二項演算子)
class MinusOperator(Operator):
    def __init__(self):
      self.name = '-'
    # 項を与えて演算を行う
    def calc(self, val1, val2):
      return val1.calc_value() - val2.calc_value()

# 値
# 値を最後まで評価するには calc_value() を使う
class Value:
    def __init__(self, v):
        self.__val = v
    def add_char(self, c):
        self.__val = self.value()  * 10 + int(c)
    def value(self):
        return self.__val
    def calc_value(self):
        v = self.value()
        #sys.stderr.write("v={}\n".format(v))
        while isinstance(v, Value):
            if v is Value:
                return v.__val
            v = v.value()
        return v
    def make_exp(self, ope, v2):
        return BinominalExpression(ope, self, v2)
    def __str__(self):
        return "{0}".format(self.__val)

# 式(値のサブクラス)
class Expression(Value):
    def __init__(self, ope):
        self.operator = ope
    # 式を評価(1段階だけ)
    def value(self):
        raise 'Not implemented!'

# 二項式(式のサブクラス)
# 演算子と右辺値と左辺値を持つ
class BinominalExpression(Expression):
    def __init__(self, ope, v1, v2):
        super().__init__(ope)
        self.val1 = v1
        self.val2 = v2
    # 式を評価(1段階だけ)
    def value(self):
        return self.operator.calc(self.val1, self.val2)
    def __str__(self):
        return "{0} {1} {2}".format(self.val1, self.operator, self.val2)

# カッコ(値のサブクラス)
# 値をカッコで囲んだ状態を表現する
class Brackets(Value):
    def __init__(self, v):
        super().__init__(v)

    def __str__(self):
        return "({0})".format(super().__str__())

# 式文字列のパーサー
class Parser:
    def __init__(self):
        self.__v1 = Value(0)  # パース中の左辺値
        self.__v2 = Value(0)  # パース中の右辺値
        self.__operator = None # パース中の演算子

    # 式が生成可能であれば生成する
    def try_make_exp(self):
        if self.__operator != None:
            self.__v1 = self.__v1.make_exp(self.__operator, self.__v2)
            self.__operator = None
            self.__v2 = Value(0)

    # パーサー本体の処理
    def parse(self, chars):
        while len(chars) > 0:
            c = chars.pop(0)
            sys.stderr.write("c={0} # {1}\n".format(c, self))
            if c == '(':
                p = Parser()
                sys.stderr.write("new parser = {0}\n".format(p))
                b = Brackets(p.parse(chars))  # カッコの中を別のパーサーで処理してカッコで囲う
                if self.__operator == None:
                    self.__v1 = b
                else:
                    self.__v2 = b
            elif c == ')':
                self.try_make_exp()
                break  # カッコが終われば処理終了
            elif c == '+':
                self.try_make_exp()
                self.__operator = PlusOperator()
            elif c == '-':
                self.try_make_exp()
                self.__operator = MinusOperator()
            else:
                if self.__operator == None:
                    self.__v1.add_char(c)
                else:
                    self.__v2.add_char(c)

        self.try_make_exp()
        return self.__v1

    def __str__(self):
        return "{3}: v1={0}, operator={1}, v2={2}".format(self.__v1, self.__operator, self.__v2, super().__str__())


chars = list(input())

p = Parser()
val = p.parse(chars)
print(val.calc_value())


# 【感想】
# パーサーでは1文字ずつ線形に解析できるようにし、カッコは再帰処理で対応した。
# 式の構造を完全にオブジェクトで保持できるようにし、最後に評価を行うことで木構造を評価していくようにした。
# C# の Expression 関連のクラス構造を思い浮かべながら、近いものを構築していった。
# こうすることで動的に式構造を変更できるようなライブラリに発展させていける可能性が広がる
#
# クラス構成について
# 値 > 式 > 二項式 というクラスの継承関係にし、
# カッコも 値 のサブクラスとすることでネストに対応できるようにした。
# 二項式には2つの値と1つの演算子を所有させ、値を評価させると演算子のcalc()を呼んでくれる仕掛けにした。
# 値を評価することで、そのサブクラスが実際の評価処理を行っていく構造であり、、木構造のどのポイントからでも
# 評価が可能となっている。
#
# Python について
# 初挑戦の Python だったが、ググる際に Python と Python3 の区別ししないといけないことに気づいた。
# クラスのインスタンスメソッドの第1引数に self を書かないといけない点、また、インスタンスメンバに
# アクセスする際に self. を付けないといけない点など、JavaScriptのような感じでとても冗長な記述と感じた。
# この辺は Ruby とは違い、明示的に書く文化が良しとされているようだ。

0