プログラムを組んでいると、「フラグAがTrueのとき、フラグBの状態を反転させたい」というシチュエーションに出くわすことがある。
If文を使うと次のように書ける。
If フラグA Then フラグB = Not フラグB End If
しかし、Xorを使用すると、次のようにIfを使わなくても1行で完結に記述することができる。
フラグB = フラグA Xor フラグB
こういう書き方が良いかどうかは別として、慣用的に使われている手法なので覚えておくと良い。(VBAではあまり見かけない)
真理値表
このコードがきちんと要件を満たしているか、表を使って確認してみよう。
以下のように、値1がTrueの場合のみ、値2が反転した結果が返ることがわかる。
Xorの真理値表
値1 | 値2 | 結果 | 値2と結果の比較 |
True | True | False | 反転 |
True | False | True | 反転 |
False | True | True | なし |
False | False | False | なし |
上記のように論理演算にTrueとFalseの全組み合わせを与えて表にしたものを真理値表という。
真理値表を出力するプログラム
さて、VBAには(And、Or、Not、Xor、Eqv、Imp)の6つの論理演算子がある。
最初の3つは比較的よく使うのだが、残りの3つは概念からしてやや難しく、使いどころも難しい。
そこで、真理値表でどういう演算なのかを確かめてみる。
たとえばImp演算の真理値表を出力してみる。
Sub Imp演算真理値表() Debug.Print "--Imp--" Debug.Print "T:T", True Imp True Debug.Print "T:F", True Imp False Debug.Print "F:T", False Imp True Debug.Print "F:F", False Imp False End Sub
出力結果はこのようになる。
--Imp-- T:T True T:F False F:T True F:F True
真理値表を出力するプログラムを出力するプログラム
プログラムで真理値表を出力するのは簡単であるが、別の演算子の真理値表を出力したいと思ったときにいちいち演算子を書き換えるのは面倒くさい。
そこでまず、次のようなプログラムを作成した。
Sub 真理値表() Debug.Print "Sub 真理値表出力()" For Each x In Split("And Or Xor Imp Eqv") Debug.Print vbTab & "Debug.Print ""--" & x & "--""" Debug.Print vbTab & "Debug.Print ""T:T"", True " & x & " True" Debug.Print vbTab & "Debug.Print ""T:F"", True " & x & " False" Debug.Print vbTab & "Debug.Print ""F:T"", False " & x & " True" Debug.Print vbTab & "Debug.Print ""F:F"", False " & x & " False" Debug.Print vbTab & "Debug.Print" Next Debug.Print "End Sub" End Sub
これを実行すると、イミディエイトウインドウに次のようなプログラムコードが出力される。
Sub 真理値表出力() Debug.Print "--And--" Debug.Print "T:T", True And True Debug.Print "T:F", True And False Debug.Print "F:T", False And True Debug.Print "F:F", False And False Debug.Print Debug.Print "--Or--" Debug.Print "T:T", True Or True Debug.Print "T:F", True Or False Debug.Print "F:T", False Or True Debug.Print "F:F", False Or False Debug.Print Debug.Print "--Xor--" Debug.Print "T:T", True Xor True Debug.Print "T:F", True Xor False Debug.Print "F:T", False Xor True Debug.Print "F:F", False Xor False Debug.Print Debug.Print "--Imp--" Debug.Print "T:T", True Imp True Debug.Print "T:F", True Imp False Debug.Print "F:T", False Imp True Debug.Print "F:F", False Imp False Debug.Print Debug.Print "--Eqv--" Debug.Print "T:T", True Eqv True Debug.Print "T:F", True Eqv False Debug.Print "F:T", False Eqv True Debug.Print "F:F", False Eqv False Debug.Print End Sub
あとはこれをコピペして実行すれば、次のような結果が得られる。
--And-- T:T True T:F False F:T False F:F False --Or-- T:T True T:F True F:T True F:F False --Xor-- T:T False T:F True F:T True F:F False --Imp-- T:T True T:F False F:T True F:F True --Eqv-- T:T True T:F False F:T False F:F True
注意点として、絶対にプログラムを間違えないこと。
私は最初に書いたとき、以下のように最後のF:Fが上からコピーしたままFalse, Trueのままにしてしまうミスを犯してしまい、真理とかけ離れた偽値表ができてしまった。
Debug.Print vbTab & "Debug.Print ""F:F"", False " & x & " True"
メタプロ
今回取り上げたようなマクロでマクロを出力するテクニックをメタプログラミングという。
コードを文字列として取り扱う際、面倒くさいのがダブルクォーテーションの扱いである。
これも次のような小道具を用意しておくと便利だ。
Sub MetaDebugPrint() Debug.Print "Debug.Print """ & Replace(inputbox(""), """", """""") & """" End Sub
実行するとインプットボックスが表示されるので、文字列化したいコードを入力する。
図の例では、イミディエイトウインドウに次のように出力される。
Debug.Print "Debug.Print ""T:T"", True And True"
これでコードを文字列としてDebug.Printするコードが出来上がったので、あとは以下のように演算子を文字列の外に出して変数に加工すれば、今回書いたようなコードが出来上がる。
Debug.Print "Debug.Print ""T:T"", True " & x & " True"
メタプログラミングでは以下の記事でもいくつか取り扱っているので、興味のある方はどうぞ。