文字列の中に、ある文字がいくつ入っているかを調べる方法を解説します。
「AA,B,CCC,DD」の中にカンマがいくつあるかを数えるコードですね。
あまりない処理ですが、「みかんいちごみかんりんごみかん」の中に「みかん」がいくつあるかという、文字「列」の登場回数のカウントも同じコードで実装できます。
最少コード量のSplit関数法
最もコード量が少なくて済むのが、Split関数を使う方法です。
登場回数 = Ubound(Split(テキスト全体, 探す文字列)) ' 実行例 MsgBox Ubound(Split("AA,B,CCC,DD", ",")) ' ← 3が表示されます。
このようにとても短いコードで実装できます。
Split関数は文字列を指定文字で分割した配列を返す関数で、
丁寧にコードを書くと、
Dim テキスト全体 As String テキスト全体 = "AA,B,CCC,DD" Dim 配列 配列 = Split(テキスト全体, 探す文字列) ' この段階で「配列」は、[AA][B][CCC][DD]の4つの文字列を格納 ' 登場回数 = 配列の要素数 - 1 Dim 登場回数 As Long 登場回数 = Ubound(配列) + 1 - 1
こういう仕組みです。
最後の式の「配列」にその中身を代入すれば、
登場回数 = Ubound(Split(テキスト全体, 探す文字列))
この式になりますね。
Uboundは配列の添字の上限を求める関数ですが、
配列は要素番号が「0」から始まるので、要素数はUBound+1です。
+1-1できれいに消えるのが気持ちいいですね。
ワークシートでも使えるReplace関数法
続いてReplace関数を使う方法です。
登場回数 = (Len(テキスト全体) - Len(Replace(テキスト全体, 検索値, ""))) / Len(検索値)
式が長いのでわかりづらいですが、
- みかんいちごみかんりんごみかん の文字数は15
- そこからみかんを消した いちごりんご の文字数は6
- 減った文字数は15-6 = 9
- 減った9文字は3文字のみかん3回分
という手順で求めています。
探す文字がカンマのように1文字の場合は、最後の割り算が1で消えるので、
登場回数 = Len(テキスト全体) - Len(Replace(テキスト全体, 探す1文字, ""))
と、ちょっと短くなります。
Split関数の方法を知った今、こっちをわざわざVBAで使う必要はありませんが、
A | B |
---|---|
みかんいちごみかんりんごみかん | みかん |
このときに、
C1 | =(LEN(A1)-LEN(SUBSTITUTE(A1,B1,"")))/LEN(B1) |
---|
と、この方法はワークシート上でも使えるいうメリットがありますので、
覚えておいて損はないと思います。
というかこんな式組むの面倒だからSplitをシート関数にしてほしいんだけど(´∀`;)
処理最速のInstr関数法
上記のような便利な関数やテクニックを使用せず、
愚直に左から探していくコードがこちらです。
Sub 文字列の登場回数をカウントする() Dim 登場回数 As Long Dim テキスト全体 As String: テキスト全体 = "みかんいちごみかんりんごみかん" Dim 検索値 As String: 検索値 = "みかん" Dim 検索値の長さ As Long: 検索値の長さ = Len("みかん") Dim 検索値の位置 As Long: 検索値の位置 = InStr(テキスト全体, 検索値) If 検索値の位置 = 0 Then 登場回数 = 0 Exit Sub End If Dim 現登場回数 As Long: 現登場回数 = 1 Do 検索値の位置 = InStr(検索値の位置 + 検索値の長さ, テキスト全体, 検索値) If 検索値の位置 = 0 Then Exit Do Else 現登場回数 = 現登場回数 + 1 End If Loop 登場回数 = 現登場回数 End Sub
長いですが、丁寧に変数名つけましたので、じっくり読めばわかると思います。
解説は不要というか、コード本体以上の解説を文章で書けません。
注意点を補足すると、
検索値の位置 = InStr(検索値の位置 + 検索値の長さ, テキスト全体, 検索値)
ここで、「前に見つかった検索値の次の検索値」を探していますが、
これを、
検索値の位置 = InStr(検索値の位置 + 1, テキスト全体, 検索値)
としてしまうと、「すもももももももものうち」から「もも」をカウントするときに、
7が答えとして返ってくるバグを生みますのでお気を付けください。
このInstr関数で左から探す方法は最速です。
上記2つの方法の、数倍のスピードが出ます。
まあ上記2つは無駄に配列を作ったり置換をして、目的の文字以外の文字たちも処理しているわけですから、当然といえば当然ですね。
ただし「コードを書く時間」もコストですので、
この方法はトータルで早いマクロとは言えないですし、
真に処理速度を求められるマクロだったとしたら、
この処理だけ数倍のスピードにしても焼け石に水です。
(検索とかセルへの出力とか、もっと時間のかかる処理を高速化しないといけないので、文字列処理は高速化の優先順位が低い)
ということで、本当にこの速度を生かすとしたら、
速度をそのままに次からはこのコードを書かなくて済むよう、
自作の関数にする必要があります。
↑上のコードをちょっと書き換えるだけなので作れる関数ですので、
Functionプロシージャを使ったことがない人も見てみてください。
Function Count文字列の登場回数(ByVal テキスト全体 As String _ , ByVal 検索値 As String) As Long Dim 検索値の長さ As Long: 検索値の長さ = Len(検索値) Dim 検索値の位置 As Long: 検索値の位置 = InStr(テキスト全体, 検索値) If 検索値の位置 = 0 Then Count文字列の登場回数 = 0 Exit Function End If Dim 現登場回数 As Long: 現登場回数 = 1 Do 検索値の位置 = InStr(検索値の位置 + 検索値の長さ, テキスト全体, 検索値) If 検索値の位置 = 0 Then Exit Do Else 現登場回数 = 現登場回数 + 1 End If Loop Count文字列の登場回数 = 現登場回数 End Function
' 関数の使用例(2が表示されます) MsgBox Count文字列の登場回数("みかんりんごみかんいちご","みかん")
これで次からは「Count文字列の登場回数」と書くだけでこの高速関数を使えます。
中身と仕組みがわかりやすい関数なので、関数化の参考になると思いますし、
勿論中身を見ずにコピペで持って帰って使ってもOKです。
しかもFunctionでつくられた自作関数は、
A | B |
---|---|
みかんいちごみかんりんごみかん | みかん |
このときに、
C1 | =Count文字列の登場回数(A1,B1) |
---|
と、シート関数として使うこともできます。
Splitの使えないシートでこれを使えるというのはかなりのメリットですよね。
最初のSplit法を読んだ時点でブラウザの戻るボタンを押してもいいところを、
こんな奥地まで読み込んでくれた酔狂なあなたに、この関数をプレゼントします。
参考にするなり、中身を見ないでコピペして使うなり、
お好きなようにお使いください。
関数づくりを勉強したいという方は、こちらの記事もどうぞ。
www.limecode.jp