VBA「Like演算子」の記事に対する注意点とか


(VBAの話です。SQLのLike演算子の話ではないので、検索から来てしまった人はごめんなさい。)

#はじめに

[【VBA入門】Like演算子(ワイルドカード、エスケープ、否定](https://www.sejuku.net/blog/33810)
これを書いている時点で「Like演算子」のGoogle検索トップがこれだった。

が、読んでところどころ解説がおかしいと感じた。[マイクロソフトの公式ドキュメント](https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/like-operator)と比べても違うところがあるし、自分が今まで覚えた知識ともややずれている。

MSの公式解説：[Like 演算子 | Microsoft Docs](https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/like-operator)

これは、そんな違和感をもとに、MS公式リファレンスを参照しながら引用元記事に「ここは違う…と思う」という事を書いた、備忘録みたいなものだ。

あらかじめ断っておくと、元記事の存在を否定するつもりはない。初心者に何かを教えるとき、細かいことを省いたほうがわかりやすいことはある。引用元サイトのようなプログラミングスクールなら集合教育が想定されるので、一番わからない人に合わせた説明方法が必要なのかもしれない。ただ、自分みたいに検索して追加の情報を調べようとしている人がいるなら、それをWebの隅っこに載せておいても害は無いだろうと考えた。引用元とこの記事の優劣を決めることは考えていないし、共存できると思っている。

また、上記マイクロソフトの公式ドキュメントを読んで理解できる人なら、この記事を読む必要はない。

VBAのエディタでF2を押すと、カーソル位置の単語のヘルプが出てくる。ほぼMS公式の説明と同じなので、そちらも参照してほしい。

更に言うと、Like演算子はVBA方言(MS方言？)で、他の言語で似たようなのは見かけない。正規表現のほうが上位互換なので、Like演算子を全く使わずプログラムを書くこともできる。人のコードを読むのには役立つが、VBAを主力として使う人でないなら、Like演算子は「とりあえず知っとく」程度にとどめて、正規表現を勉強したほうがよいと思う。


と、予防線を張ったところで本編開始。

#「ワイルドカード」という用語の使い方について
元記事ではLike演算子で使える特殊記号をすべて「ワイルドカード」と言ってしまっているせいで、全体におかしな文章になってしまっている。

>ちなみに変数pattern内で使われいる”[ ]”はワイルドカードで使用される文字で、ワイルドカードとそれに使われる文字については後ほど解説します。

>ワイルドカードで使われる文字について表にまとめした。
>
>|文字           | 説明  |
>|:--------------|:------------------|
>| *             |任意の1文字 |
>| ?             |0文字以上の文字|
>| #             |0～9の半角数字 |
>| [charlist]           |charlistに含まれる全角または半角の1文字 |
>| [!charlist]           |charlistに含まれない全角または半角の1文字 |

少なくとも「[charlist]」みたいなのをワイルドカードは呼ばない。[ワイルドカード](https://ja.wikipedia.org/wiki/ワイルドカード_(情報処理)) と言ったときには、主に「*」や「?」を指す。「#」がワイルドカードと呼ばれているかはちょっとわからない[^1]。

少なくとも、公式ドキュメントは「ワイルドカード文字」と「文字のリスト」を区別している。

>パターン マッチング機能では、ワイルドカード文字、文字のリスト、または文字の範囲を任意に組み合わせて使用し、文字列に一致させることができます。
>(上記と同じ表)


序盤にこういう定義をしてしまったせいで、後に続く「ワイルドカードのエスケープ」など、全体に違和感が出てしまっている。

そもそも同じ記事の冒頭では、
>ワイルドカード文字や文字のリスト、文字の範囲を組み合わせて正規表現に近いパターンマッチングを行うことができます。

とマイクロソフトと同じ説明をしていて、一貫していない。

単に言葉の問題かもしれないが、この文章の「ワイルドカード」の定義を鵜呑みにすると、他の人と話すときにすれ違いが起きるかもしれないと思った。「ワイルドカード」を「* ?」のことだと思って話をしていたら「``[ABC]``」のことだった、なんてことが起きると混乱する。「ワイルドカード」といったら、主には「* ?」だと思ったほうがいいかもしれないよ、という話。

逆にこちら側は「``[ABC]``をワイルドカードと習った人がいるから、話をするとき気を付けないといけないな」というところ。

[^1]: 自分があまり使わないため。

#「ワイルドカードのエスケープ」の部分
この記事の言う「ワイルドカード」の定義が不正確なのは前述のとおり。とりあえず「特殊記号」と読み替えることにして進める。

>ワイルドカードで使われる文字は”[ ]”で囲むことでエスケープすることができます


続いてサンプルコードで
>```vb
>pattern = "*[!]*"
>```

を紹介している。


これは動くのだけれど、例に「!」を使ったのは適切でなかったというか、仕様に従うなら「！」は必ず括弧で囲わなくてもいい。そう公式には書いてある。

>感嘆符 (!) を charlist の前に置くと、string の中の charlist 以外の文字に一致します。 角かっこの外側で使用すると、感嘆符そのものに一致します。


というわけでサンプルコードは

```vb
pattern = "*!*"
```

でも正しい。間違っていないのだけれど、Google検索上位の記事としては、ちょっとツッコミの余地があるところ。

ただ、これを「ちゃんと」解説する場合、正確に説明するのは難しい。自分も今回調べるまでなんとなくしか把握していなかったのだけれど、

* 角かっこ ([)、疑問符 (?)、番号記号 (#)、アスタリスク (*) に一致させるときは[]が必ず必要。
* 「!」は[]の先頭に書いたときのみ否定の意味になる[^2]。
* ハイフン(-)は[]の先頭や末尾の時はハイフンそのものにマッチする。[A-Z]などと書いたときには文字範囲の特殊記号として扱われる

[^2]: 途中に書いたときには触れていない、試していないので不明

など、「VBA『入門』」で教えるには複雑な中身になっている(たぶん教えても覚えきれない)。

1回分の内容で伝えられることには限りがあるので、上記のようなことまで説明はいらないと思うが[^3]、少なくともサンプルコードは[?]にしておけばよかったと思う。

[^3]: この記事はそういうことを補いたいので書いている。

そして、さらに加えて言うならば、「!」を必ず括弧でくくる必要はないが、「必ず括弧でくくれ」という教え方も良いんじゃないかと思う。

覚えたての人だと、「[]内では否定として使う、それ以外では普通の文字と同じ」「``[!]``だとそのままなのに```[!ABC]```にしたら意味が変わる」というのを最初は理解できないかもしれない。

たとえば、習いたての人が、

```vb

str="what!" 'what! や What? が入ってくる

'文字列が「!」で終わっていたらhogehogeする
If str Like "*[!]" Then hogehoge 'hogehogeされる

'文字列が「?」で終わっていたらhogehoge2する
If str Like "*[?]" Then hogehoge2 'hogehoge2される

'文字列が「!」か「?」で終わっていたらhogehoge3する
If str Like "*[!?]" Then hogehoge3 'hogehoge3されない。なんで？
```

みたいなのを書いて悩む(そしてデバッグに何時間もかかってプログラミングが嫌になる)ことは、好ましくないと思う。「今まで動いていたプログラムが1文字違いで動かなくなる」というのは上級者の悩みだ[^4]。

[^4]: 悩むのが楽しいという人もいる。

だから、初心者のうちは

```vb
'「!」「?」で終わっていたらhogehogeする
'特殊記号は念のため他と混ぜないで使う
If str Like "*[!]" Or str Like "*[?]" Then hogehoge 
```

と、かならず[!]を単独でかっこの中に入れてしまうように指導してしまうのもアリなんじゃないか、と思っている。ただこの調子で長々とorを書かれても困るので、慣れてきたら(慣れたころには複雑なことも書けるようになっている)変えるようにする、とか。


なお、元記事は「ワイルドカードで使われる文字は”[ ]”で囲むことでエスケープすることができます」としているが、「右角かっこはどう頑張っても[]グループ内で使用できない」と公式が明言している(後半にサンプルコードもある)。
>注意
>
>特殊文字の左角かっこ ([)、疑問符 (?)、番号記号 (#)、およびアスタリスク (*) に一致させるには、それらを角かっこで囲みます。 右角かっこ自体に一致させるのに、右角かっこ (]) をグループ内で使用することはできませんが、個々の文字としてグループの外側で使用することはできます。

``[[]``はできるけれど``[]]``はできない。Like演算子の限界を感じた。

#「大文字小文字の区別なしで使用するには」の部分
(言いたいことの下書きのみ)

* [Option Compare Text](https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/option-compare-statement) は、文字マッチだけでなく、不等号比較の結果にも影響する。またモジュール全体に影響する。副作用が大きいので、頻繁に書き換えるコードでは使わないほうがいい。しかしコードは使い続けている限り書き換えが発生する。したがって、ほとんどのコードでは使わないほうがいい。
* UCase、LCaseの方法は使えるが、部分的に大文字・小文字にしたい場合(けっこうある)にはindexやinstrなどを組み合わせることになる。あれこれと文字列をいじると、すっきりしたコードから遠ざかってしまう。ただ数文字をマッチングしたいだけなのに。
* 個人的には、複雑なことを書く必要があったら、それはLike演算子の限界と考えて、正規表現の検討をお勧めしたい。右角かっこのように、どうしても表現できないものがLike演算子にはある。出来る出来ないより、向き不向きの問題。

#終わりに

* Microsoftの公式サイトはどんどん読みましょう。
* VBAのソース上でF2押すとヘルプが出るので、どんどん使いましょう。
* ググったときには複数サイト見比べましょう。面倒でも、ググらないよりはましです。どんどんググりましょう。