Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonで文字列として与えられたブール式を評価する方法

「and」や「or」といった論理演算子を含むブール式が、文字列 s として与えられたとします。この式を評価し、その結果を返すのが本記事の目的です。式には括弧が含まれる場合があり、括弧で囲まれた部分は最優先で評価する必要があります。

たとえば、入力が s = "T and (F or T)" であれば、出力は True になります。

解決の手順

この問題は、スタック(リスト)を活用することで効率的に解けます。全体の流れは以下の通りです。

  1. スタックの初期化:空のリスト stack を用意します。
  2. トークン化:文字列 s を空白区切りで分割し、トークンのリストを作成します。
  3. 各トークンの処理:各トークン v に対して、次のように判定と処理を行います。
    • v が「(」で始まる場合 → 括弧を取り除いた残りの部分が「T」であるかを判定し、その真偽値をスタックへプッシュします。
    • v に「)」が含まれる場合 → 閉じ括弧の個数を ct とし、括弧を除いた部分が「T」かどうかを判定してスタックへプッシュします。続いて ct 回ポップを行い、右辺・演算子・左辺を取り出して演算を実行し、その結果をスタックに戻します。
    • v が「T」または「F」の場合 → v が「T」と等しいかどうかの真偽値をスタックへプッシュします。
    • 上記以外(演算子)の場合 → 演算子に対応する関数 op[v] をスタックへプッシュします。
  4. 最終的な集計:すべてのトークンを処理した後、スタックに複数の要素が残っている場合は、左側から順に演算子を適用して畳み込みを行い、スタックの先頭要素を結果として返します。要素が 1 つだけの場合は、その値をそのまま返します。

それでは、実際の実装例を見ていきましょう。

実装例(Pythonコード)

class Solution:
    def solve(self, s):
        stack = []
        op = {
            "or": lambda x, y: x or y,
            "and": lambda x, y: x and y,
        }
        for v in s.split():
            if v[0] == "(":
                stack.append(v[v.count("(") :] == "T")
            elif v.count(")") > 0:
                ct = v.count(")")
                stack.append(v[:-ct] == "T")
                for _ in range(ct):
                    right = stack.pop()
                    o = stack.pop()
                    left = stack.pop()
                    stack.append(o(left, right))
            elif v in ["T", "F"]:
                stack.append(v == "T")
            else:
                stack.append(op[v])

        if len(stack) > 1:
            for i in range(0, len(stack) - 1, 2):
                stack[i + 2] = stack[i + 1](stack[i], stack[i + 2])
            return stack[-1]

        return stack[0]

ob = Solution()
s = "T and (F or T)"
print(ob.solve(s))

入力

"T and (F or T)"

出力

True

コードのポイント

  • 演算子「and」「or」は、それぞれ2つの引数を受け取るラムダ式として辞書 op に登録しておき、必要なときに呼び出せるようにしています。
  • 「(F」や「T)」のように、値と括弧が同じトークンに含まれるケースにも対応できるよう、括弧の個数を数えてスライスで除去しています。
  • 閉じ括弧「)」が現れた時点で直前の演算を確定させることで、括弧内の式を優先的に評価する仕組みを実現しています。
  • 最後にスタックへ複数の要素が残る場合は「値・演算子・値…」という並びになるため、2つずつ間隔をあけてループし、左から順に演算を適用していきます。

このようにスタックを使った処理を組み合わせることで、文字列形式のブール式でも括弧の優先順位を正しく守りながら評価できます。条件式を動的に扱いたい場面などで応用できるテクニックなので、ぜひ参考にしてください。

  1. Pythonで文字列からn番目の文字を削除するプログラムの書き方

    はじめにこの記事では、以下の問題に対する解決方法を解説します。問題文 − 与えられた文字列から、指定したインデックス(i番目)の文字を削除し、その結果を表示します。Pythonの文字列では、インデックスは必ず0から始まるという点に注意してください。例えば、「Tutorialspoint」という文字列の場合、各文字のインデックスは以下のように対応しています。T u t o r i a l s p o i n t 0 1 2 3 4 5 6 7 8 9 10 11 12 13それでは、この問題を解決するためのPythonスクリプトを見ていきましょう。実装例def remove(string

  2. Pythonで文字列からn番目の文字を削除する方法【サンプルコード付き】

    Pythonにおいて、文字列は文字の配列として扱われます。そのため、先頭の文字のインデックスは「0」から始まり、各文字の位置(インデックス)を簡単に取得できます。この性質を利用すると、指定したn番目の文字だけを削除することが可能です。 基本的な考え方はシンプルです。削除したい文字のインデックス番号を受け取り、元の文字列を次の2つの部分文字列に分割します。 n番目のインデックスの文字より前の部分 n番目のインデックスの文字より後の部分 その後、この2つの部分文字列を連結すれば、n番目の文字が取り除かれた新しい文字列が完成します。 実行例 入力: python 削除するインデックス: 3 出