Excelにおけるワイルドカードと、カウント系関数の挙動


はじめに

これは、調べ物をして気付いた事の記録です。関数やワイルドカードの知識を把握しているのを前提。VBAの内容も含まれます。

ワイルドカードとCOUNT系関数と空白と

発端

Xで次のような話があった。

ExcelのCOUNTIF関数の第2引数、検索条件について、
ワイルドカードを表現する文字である*(アスタリスク)を入力した場合、数値が数えられない
という。

アスタリスク検索の挙動

Excelにおけるワイルドカードの*(アスタリスク)は

  1. どの値でも

  2. どんな長さでも

検索するのを表現するものだ。

任意の
文字数 たとえば、*east は "北東部" と "南東部" を検索します

検索でのワイルドカード文字の使用 - Microsoft サポート

日本語の解説は、翻訳と改行がおかしいが、英語では

Any number of characters
For example, *east finds "Northeast" and "Southeast"

Using wildcard characters in searches - Microsoft Support

こう。どんな値でも、どんな長さでも良いのだから、検索条件として単にアスタリスクを1つ入れれば、
何らかの値がセルに入っていればそれがヒットする
事が期待される。

実験のため、テーブルを作る。

data_table

テーブル名はdata_table。上から順にデータを、

  • 数値が5つ

  • 文字列が5つ

  • 空白(何も入れない)が5つ

このように格納している。ここでデータ部を選択して検索(Ctrl+Fなど)し、検索条件に半角アスタリスクを1つ入れて、すべて検索を実施する。

ワイルドカード:半角アスタリスクのみで検索

結果、上図のように10セルがヒットする。数値と文字列が5つずつ入力されているので、それがヒットするわけだ。

冒頭の話に戻る。

COUNTIFにワイルドカードを指定すると、数値はカウントされないと知った。

冒頭の参照ポスト

これによると、COUNTIF関数で同じ検索条件(アスタリスク1つ)で検索をおこなうと、数値は数えられないという事だった。であれば、いま実験のために作ったデータでCOUNTIF関数を使えば、結果は5が返ってくるはず。やってみる。

数式を入れる。

=COUNTIF(data_table,"*")
数式を入力

そうすると、

5が返ってくる

なるほど、確かに5が返ってきた。アスタリスクは、空白で無ければ何でも数えるはずだったのに。

アスタリスクの役割の違い

ここで、COUNTIF関数の仕様を調べる。

セル範囲 A2 ~ A5 に含まれるセルのうち、任意のテキストが入力されているセルの個数を求めます。 ワイルドカード文字 (*) は、任意の文字列を表します。 結果は 4 です。

COUNTIF 関数 - Microsoft サポート

疑問符は任意の 1 文字に相当します。 アスタリスクは任意の一連の文字列に相当します。

COUNTIF 関数 - Microsoft サポート

なんと、COUNTIF関数におけるワイルドカードの半角アスタリスクは、
あらゆる文字列
を表現するものだという。なるほど数値はヒットしないはずだ。つまりこれは、

  • Excelの機能である検索の条件

  • ワークシート関数での条件

このそれぞれで、役割が異なるのを意味する。大変ややこしい。もっとも、Excelではこういうのは結構ある。同じような名前を持つ、実装の経緯が異なるワークシート関数とVBAの関数でしくみが違ったり、など。

最初に紹介したポストの投稿者は、COUNTIF関数の代わりにCOUNTA関数を使ったと言う。COUNTA関数は、
空白ではないセルの個数
を返す関数であり、数値でも文字列でも良いので、何らかの値が入っているセルを数えるのが投稿者の目的であるのがうかがえる。では、COUNTIF関数では、同じような機能は達成できないのだろうか。

COUNTIF関数による空白カウント

色々の表計算アプリケーションやプログラミング言語では、空白との比較で

""

を使う。引用符(Excelでは二重引用符)を2つ続けたものが空白を表現するので、これに、=や<>などの比較演算子をくっつけて判定する。実験しよう。

空白との比較

テーブルに列を追加し、空白と比較をおこなう数式を入れた。

=[@データ]=""

この数式は、同じ行にあるデータフィールドの値と空白が同じであるかを判定する。同じならTRUE、異なるならFALSEを返す。
結果は当然、下から5個のセルにTRUEが入る。その上の10個のセルは、数値または文字列が入っているから、FALSE。であれば、これをCOUNTIFの条件として投入すれば、空白以外のセルを数えられるだろうか。

二重引用符を2つ続ける(「""」)と空白を表現できるのだった。いまは、空白以外のセルを数えたいのだから、条件として、

<>""

これを入れよう。つまり、空白に等しく無いセルを探したい。

セルに二重引用符はそのまま入れられないので、入力は

=COUNTIF(data_table,"<>""""")

こうする。二重引用符は文字列を囲む記号なので、それ自体を文字列として扱う(エスケープする)場合、2つ続ける。

  • =""""→"

  • =""""""→""

というようになる。<>""を表現するのは<>""""だから、それを最後に二重引用符で囲めば"<>"""""となる。

15が返ってくる

15が返ってきた。空白も数えられてしまっている。COUNTIF関数では無理なのだろうか。

実は、COUNTIF関数でも出来る。<>""なる条件を指定するという事をせず、

<>

ただこのようにする。

10が返ってくる

これは、なかなか興味深い挙動。=や<や>は比較演算子なのだから、比較対象が必要なはず。であるから、先ほどは比較対象の空白を示す、2つ繋げた二重引用符を入力したのだけれど、それでは失敗したのだった。しかるに、単に比較演算子のみ(「<>」)を入れた場合、
空白との比較
がなされるようだ。面白い。
という事は。<>の否定は=なので、比較演算子として単に=を入れれば…

5が返ってきた

5が返ってきた。<>で空白以外のセルが数えられたので、その否定である=を入力したので、空白に等しいセルが数えられた、という寸法。

COUNTBLANK関数の挙動

検算してみよう。

名前つき範囲「検索範囲」
ランダムに空白と1を入れた

適当な範囲を決めて、セル範囲の名前に検索範囲と設定した。そこに、数式を使ってランダムに、空白と1を入れた。ここにある空白をそれぞれ、

  • COUNTIF関数

  • COUNTBLANK関数

で数える。COUNTBLANK関数は空白を数える関数なので、もしCOUNTIF関数の検索条件を=や<>とした場合に空白と比較するのだとすれば、条件を=にしたら、COUNTBLANK関数の結果と一致するはず。

一致しない

…一致しない。なぜだろう?

試しに、空白の所、B1セルでDELETEキーを押してみる。

増えた!

COUNTIF関数での個数が増えた。そういえば、ランダムにデータを入れる時、IF関数で判定して、""と1に分けたのだった。その後に値の貼り付けをした。つまり、表示は空白であっても、セル内容が空では無いので、それが反映されたという事か。であれば、COUNTIF関数で単に<>や=を入れた場合、比較対象となるのは、値が
空白文字列なのでは無い
と推察できる。

セル状態の確認

再度、COUNTIF関数の結果が0の状態に戻して…

結果が0の状態

B1セルの状態をVBAで見てみる。

適当なコード

適当にコードを書いて、選択したB1セルの状態を確認する。

ローカルウインドウ

ローカルウインドウでB1セルの状態を見る。DELETEキーで結果が変化するので、怪しいのはVALUEプロパティ方面。

VALUE2プロパティ

VALUE2プロパティが

""

になっている。ランダムに値を入れた時に、値の貼り付けでそうしたので当然。

空セルと空白文字列

念のために、セルがEmptyであるかを判定して確認してみると、

イミディエイトウインドウでIsEmpty関数を使って確認

IsEmpty関数の結果がFalseになる。という事は、このセルの値をEmptyにしてやれば…

個数が増えた

COUNTIF関数の結果である個数が増えた。つまり、COUNTIF関数の検索条件に、=や<>のみを入れ比較対象を入れない場合、実際の比較対象は
Empty
である事が示唆される。値が空白文字列なのでは無い、というわけだ。
それなら、次のようなコードを実行すれば、

空白文字列をEmptyにするコード
For Eachループなのは簡単のため
一致した

やっと結果が一致した。やはり、COUNTIFのほうは
空白文字列(「""」)を比較対象としているのでは無い
と考えられる。だから、表面上は同じに見える

  • 空のセル

  • 空白文字列が入ったセル

これらを対象とすると、結果が異なるという事。
ちなみに、MicrosoftによるCOUNTBLANK関数のリファレンスには、
empty cells
とともに、
"" (empty text)
も数える対象とするのが明記されている。

いっぽう、COUNTA関数の場合は、

COUNTA 関数では、エラー値や空の文字列 ("") を含め、すべての種類のデータを含むセルが計算の対象となります。 たとえば、セル範囲に空の文字列を返す数式が含まれている場合、COUNTA 関数はその値を計算の対象とします。 COUNTA 関数は空白セルを計算の対象にしません。

COUNTA 関数 - Microsoft サポート

空白文字列は数える対象とし、空白セル(Empty)を計算の対象にしないと書いてある。これであれば、COUNTIF関数と同じような機能となる。ここから言えるのは、
COUNTA関数とCOUNTBLANK関数は相補的では無い
という事。つまり、セルにたとえば、

=""

これを入れた場合、COUNTA関数では(Emptyで無いので)数えられ1増えるが、COUNTBLANK関数で数えられるのは減らない(空白文字列をカウントするから)

空白文字列 ("") を返す数式が入力されているセルも計算の対象となります。 ただし、数値として 0 (ゼロ) を含むセルは計算の対象となりません。

COUNTBLANK 関数 - Microsoft サポート

COUNT系関数の振る舞い

だから、ある範囲に対して、COUNTA関数の結果とCOUNTBLANK関数の結果を足しても、その範囲に属するセル数と一致するとは限らないわけだ。

セル内容とCOUNT系関数の関係
ISBLANKとCOUNTBLANKが合わないのがまたややこしい

上図に、データ内容によってCOUNT系関数がどのように機能するかを記載した。
データ部の11から15番目までは、表面上は何も表示されないので同じように見えるが、12番目と14番目には、数式として

=""

を入れてある。COUNTBLANK関数は、EmptyとBlankを両方数えるが、実務上はそれらを区別せず、
見た目が空白
であるのを数えるほうが多いので(実務では数式の結果が重要だから)、その観点からは合理的な実装だと言える。

終わりに

私は実務で、COUNTIF以外のCOUNT系関数を滅多に使わないので、COUNTAやCOUNTBLANKの関数のリファレンスもちゃんと参照した事が無く、振る舞いについてよく理解していなかったので、色々と調べて勉強になりました。

参考資料


いいなと思ったら応援しよう!