Excelにおけるワイルドカードと、カウント系関数の挙動
はじめに
これは、調べ物をして気付いた事の記録です。関数やワイルドカードの知識を把握しているのを前提。VBAの内容も含まれます。
ワイルドカードとCOUNT系関数と空白と
発端
Xで次のような話があった。
ExcelのCOUNTIF関数の第2引数、検索条件について、
ワイルドカードを表現する文字である*(アスタリスク)を入力した場合、数値が数えられない
という。
アスタリスク検索の挙動
Excelにおけるワイルドカードの*(アスタリスク)は
どの値でも
どんな長さでも
検索するのを表現するものだ。
日本語の解説は、翻訳と改行がおかしいが、英語では
こう。どんな値でも、どんな長さでも良いのだから、検索条件として単にアスタリスクを1つ入れれば、
何らかの値がセルに入っていればそれがヒットする
事が期待される。
実験のため、テーブルを作る。
テーブル名はdata_table。上から順にデータを、
数値が5つ
文字列が5つ
空白(何も入れない)が5つ
このように格納している。ここでデータ部を選択して検索(Ctrl+Fなど)し、検索条件に半角アスタリスクを1つ入れて、すべて検索を実施する。
結果、上図のように10セルがヒットする。数値と文字列が5つずつ入力されているので、それがヒットするわけだ。
冒頭の話に戻る。
これによると、COUNTIF関数で同じ検索条件(アスタリスク1つ)で検索をおこなうと、数値は数えられないという事だった。であれば、いま実験のために作ったデータでCOUNTIF関数を使えば、結果は5が返ってくるはず。やってみる。
数式を入れる。
=COUNTIF(data_table,"*")
そうすると、
なるほど、確かに5が返ってきた。アスタリスクは、空白で無ければ何でも数えるはずだったのに。
アスタリスクの役割の違い
ここで、COUNTIF関数の仕様を調べる。
なんと、COUNTIF関数におけるワイルドカードの半角アスタリスクは、
あらゆる文字列
を表現するものだという。なるほど数値はヒットしないはずだ。つまりこれは、
Excelの機能である検索の条件
ワークシート関数での条件
このそれぞれで、役割が異なるのを意味する。大変ややこしい。もっとも、Excelではこういうのは結構ある。同じような名前を持つ、実装の経緯が異なるワークシート関数とVBAの関数でしくみが違ったり、など。
最初に紹介したポストの投稿者は、COUNTIF関数の代わりにCOUNTA関数を使ったと言う。COUNTA関数は、
空白ではないセルの個数
を返す関数であり、数値でも文字列でも良いので、何らかの値が入っているセルを数えるのが投稿者の目的であるのがうかがえる。では、COUNTIF関数では、同じような機能は達成できないのだろうか。
COUNTIF関数による空白カウント
色々の表計算アプリケーションやプログラミング言語では、空白との比較で
""
を使う。引用符(Excelでは二重引用符)を2つ続けたものが空白を表現するので、これに、=や<>などの比較演算子をくっつけて判定する。実験しよう。
テーブルに列を追加し、空白と比較をおこなう数式を入れた。
=[@データ]=""
この数式は、同じ行にあるデータフィールドの値と空白が同じであるかを判定する。同じならTRUE、異なるならFALSEを返す。
結果は当然、下から5個のセルにTRUEが入る。その上の10個のセルは、数値または文字列が入っているから、FALSE。であれば、これをCOUNTIFの条件として投入すれば、空白以外のセルを数えられるだろうか。
二重引用符を2つ続ける(「""」)と空白を表現できるのだった。いまは、空白以外のセルを数えたいのだから、条件として、
<>""
これを入れよう。つまり、空白に等しく無いセルを探したい。
セルに二重引用符はそのまま入れられないので、入力は
=COUNTIF(data_table,"<>""""")
こうする。二重引用符は文字列を囲む記号なので、それ自体を文字列として扱う(エスケープする)場合、2つ続ける。
=""""→"
=""""""→""
というようになる。<>""を表現するのは<>""""だから、それを最後に二重引用符で囲めば"<>"""""となる。
15が返ってきた。空白も数えられてしまっている。COUNTIF関数では無理なのだろうか。
実は、COUNTIF関数でも出来る。<>""なる条件を指定するという事をせず、
<>
ただこのようにする。
これは、なかなか興味深い挙動。=や<や>は比較演算子なのだから、比較対象が必要なはず。であるから、先ほどは比較対象の空白を示す、2つ繋げた二重引用符を入力したのだけれど、それでは失敗したのだった。しかるに、単に比較演算子のみ(「<>」)を入れた場合、
空白との比較
がなされるようだ。面白い。
という事は。<>の否定は=なので、比較演算子として単に=を入れれば…
5が返ってきた。<>で空白以外のセルが数えられたので、その否定である=を入力したので、空白に等しいセルが数えられた、という寸法。
COUNTBLANK関数の挙動
検算してみよう。
適当な範囲を決めて、セル範囲の名前に検索範囲と設定した。そこに、数式を使ってランダムに、空白と1を入れた。ここにある空白をそれぞれ、
COUNTIF関数
COUNTBLANK関数
で数える。COUNTBLANK関数は空白を数える関数なので、もしCOUNTIF関数の検索条件を=や<>とした場合に空白と比較するのだとすれば、条件を=にしたら、COUNTBLANK関数の結果と一致するはず。
…一致しない。なぜだろう?
試しに、空白の所、B1セルでDELETEキーを押してみる。
COUNTIF関数での個数が増えた。そういえば、ランダムにデータを入れる時、IF関数で判定して、""と1に分けたのだった。その後に値の貼り付けをした。つまり、表示は空白であっても、セル内容が空では無いので、それが反映されたという事か。であれば、COUNTIF関数で単に<>や=を入れた場合、比較対象となるのは、値が
空白文字列なのでは無い
と推察できる。
セル状態の確認
再度、COUNTIF関数の結果が0の状態に戻して…
B1セルの状態をVBAで見てみる。
適当にコードを書いて、選択したB1セルの状態を確認する。
ローカルウインドウでB1セルの状態を見る。DELETEキーで結果が変化するので、怪しいのはVALUEプロパティ方面。
VALUE2プロパティが
""
になっている。ランダムに値を入れた時に、値の貼り付けでそうしたので当然。
空セルと空白文字列
念のために、セルがEmptyであるかを判定して確認してみると、
IsEmpty関数の結果がFalseになる。という事は、このセルの値をEmptyにしてやれば…
COUNTIF関数の結果である個数が増えた。つまり、COUNTIF関数の検索条件に、=や<>のみを入れ比較対象を入れない場合、実際の比較対象は
Empty
である事が示唆される。値が空白文字列なのでは無い、というわけだ。
それなら、次のようなコードを実行すれば、
やっと結果が一致した。やはり、COUNTIFのほうは
空白文字列(「""」)を比較対象としているのでは無い
と考えられる。だから、表面上は同じに見える
空のセル
空白文字列が入ったセル
これらを対象とすると、結果が異なるという事。
ちなみに、MicrosoftによるCOUNTBLANK関数のリファレンスには、
empty cells
とともに、
"" (empty text)
も数える対象とするのが明記されている。
いっぽう、COUNTA関数の場合は、
空白文字列は数える対象とし、空白セル(Empty)を計算の対象にしないと書いてある。これであれば、COUNTIF関数と同じような機能となる。ここから言えるのは、
COUNTA関数とCOUNTBLANK関数は相補的では無い
という事。つまり、セルにたとえば、
=""
これを入れた場合、COUNTA関数では(Emptyで無いので)数えられ1増えるが、COUNTBLANK関数で数えられるのは減らない(空白文字列をカウントするから)。
COUNT系関数の振る舞い
だから、ある範囲に対して、COUNTA関数の結果とCOUNTBLANK関数の結果を足しても、その範囲に属するセル数と一致するとは限らないわけだ。
上図に、データ内容によってCOUNT系関数がどのように機能するかを記載した。
データ部の11から15番目までは、表面上は何も表示されないので同じように見えるが、12番目と14番目には、数式として
=""
を入れてある。COUNTBLANK関数は、EmptyとBlankを両方数えるが、実務上はそれらを区別せず、
見た目が空白
であるのを数えるほうが多いので(実務では数式の結果が重要だから)、その観点からは合理的な実装だと言える。
終わりに
私は実務で、COUNTIF以外のCOUNT系関数を滅多に使わないので、COUNTAやCOUNTBLANKの関数のリファレンスもちゃんと参照した事が無く、振る舞いについてよく理解していなかったので、色々と調べて勉強になりました。