テキストからある文字列を検索し、それより右側を取得するコードを解説します。
捉え方が違うだけで同じことなので、ある文字列から左側を削除するとも言えますね。
はじめに
今回のコードは文字列操作の基本Right/Mid関数とInstr関数を使って処理をする場合、
' 1文字を探す場合 ある文字より右側の部分 = Right(元の文字列, Len(元の文字列) - InStr(元の文字列, 検索文字)) ' 2文字以上の文字列を探す場合 ある文字列より右側の部分 = Mid(元の文字列, InStr(元の文字列, 検索文字列) + Len(検索文字列))
と、割とめんどくさいコードになります。
↑の基本の書き方も重要なので覚える必要があると思いますが、
元の文字列にそこまで癖がないときは、↓の技も使えます。
' Split関数を利用した短縮技 ある文字列より右側の部分 =Split(元の文字列, 検索文字列)(1)
Split関数で文字列を分割する方法だと、かなり短く書くことができます。
※ 文字列が1回しか出てこない場合限定です
まずは文字列操作の基本であるRight/Mid/Instr関数から解説しますが、
そんな複雑な処理はしなそうだから短縮コードだけでいいという方は、
Split関数の解説から読んでいただいても問題ありません。
お好きな順番でお読みください。
探す文字列が1文字の場合
この処理を行う方法は二つありますので、お好きな方を採用してください。
' ① 文字を取ってくる「文字数」に注目して、右からその数だけRightで取ってくるバージョン ある文字より右側の部分 = Right(元の文字列, Len(元の文字列) - InStr(元の文字列, 検索文字)) ' ② 文字を分割する「位置」に注目して、そこから左をMidで捨てるバージョン ある文字より右側の部分 = Mid(元の文字列, InStr(元の文字列, 検索文字) + 1)
実行サンプル
商品名 = "愛媛産みかん" 検索値 = "産" ' ① 右から取ってくるバージョン 種類 = Right(商品名, Len(商品名) - InStr(商品名, 検索値)) ' ② 左を捨てるバージョン 種類 = Mid(商品名, InStr(商品名, 検索値) + 1) MsgBox 種類 ' ← ①②どちらでやっても「みかん」が表示されます。
解説①:右から取ってくるバージョン
Instr関数で求めた「検索値の位置」は、検索値が1文字なら「検索値までの文字数」と言い換えることができます。
「全体の文字数 - 検索値までの文字数」が目的の文字数ですので、
それをRight関数で取ってくれば完成ですね。
解説②:左を捨てるバージョン
Instr関数で求めた「検索値の位置」の、次の文字から先が欲しい部分になります。
Mid関数を使うと、「○文字目から△文字」を取ってくることができますが、
この△を省略した場合は、右側全部を取ってきますので、
Mid(元の文字列, 検索値の位置 + 1)で目的の右側が取得できます。
①・②どちらを使っても問題ないですが、どちらを使うにせよ、
If InStr(商品名, 検索値) > 0 Then 種類 = Right(商品名, Len(商品名) - InStr(商品名, 検索値)) Else 種類 = "" End If
この「検索値が見つからなかったとき用のIf文」は必ず用意して下さい。
Left+Instrの場合と違い、RightやMidはInstrの結果が0でもエラーにはなりませんので、ちゃんとIf文を用意しておかないと、不具合が起きたことにすら気づけない危険性があります。
探す文字が2回出てくる場合
探す文字が2個ある場合は、どちらを探すのかによって使う関数が変わります。
例えば「○○データ(2021.8).xlsx」から拡張子を取り出す場合などですね。
「.」が二つありますので、後者を探す場合はInstr関数は使えません。
この場合の対応は簡単で、
①②どちらの場合もInstr関数を右から探すInstrRev関数に変えるだけでOKです。
種類 = Right(商品名, Len(商品名) - InStrRev(商品名, 検索値)) 種類 = Mid(商品名, InStrRev(商品名, 検索値) + 1)
InstrRev関数は「右から探す」関数ですが、見つけた位置はInstr関数と同じく「左から何文字目か?」を教えてくれます。
なので、特別計算式を差し替える必要はありません。
探す文字列が2文字以上の場合
2文字以上の文字列を検索する場合は少し複雑になります。
1文字コード同様、「右から取ってくる」「左を捨てる」の2パターンがあります。
' ① 文字を取ってくる「文字数」に注目して、右からその数だけRightで取ってくるバージョン ある文字列より右側の部分 = _ Right(元の文字列, Len(元の文字列) - InStr(元の文字列, 検索文字列) - Len(検索文字列) + 1) ' ② 文字を分割する「位置」に注目して、そこから左をMidで捨てるバージョン ある文字列より右側の部分 = _ Mid(元の文字列, InStr(元の文字列, 検索文字列) + Len(検索文字列))
1文字バージョンと比べるとだいぶ①が面倒になっていますので、
こちらは②を採用した方が良いかもしれません。
ちなみに当たり前といえば当たり前ですが、Len(検索文字列)に1を代入すれば、1文字を探すバージョンの式と一致します。
2文字以上を探す場合と書きましたが、1文字以上のすべての文字列で使えるコードということですね。
実行サンプル
商品名 = "愛媛県産みかん" 検索値 = "県産" ' ① 右から取ってくるバージョン 種類 = Right(商品名, Len(商品名) - InStr(商品名, 検索値) - Len(検索文字列) + 1) ' ② 左を捨てるバージョン 種類 = Mid(商品名, InStr(商品名, 検索文字列) + Len(検索文字列)) MsgBox 種類 ' ← ①②どちらでやっても「みかん」が表示されます。
解説①:右から取ってくるバージョン
Instr関数で求めた「検索値の位置」は、検索値が1文字なら「検索値までの文字数」と言い換えることができましたが、
検索値が2文字以上の場合はそうとは言えません。
Instr関数は「探す文字列が始まる最初の1文字目」の位置を返す関数ですので、
Right関数に渡す「取ってくる文字数」を計算するには、
「全体の文字数 - 検索値の開始位置までの文字数 - (検索値の文字数 - 1)」
と、足りない分の「検索値の文字数-1」をさらに引かないといけません。
複雑ですね(´∀`;)
解説②:左を捨てるバージョン
こっちは2文字以上になっても割とわかりやすいです。
まずは「検索文字列も含めて右側」を取ってきましょう。
ある文字列を含めた右側部分 = Mid(元の文字列, InStr(元の文字列, 検索文字列))
検索文字を入れるので、ストレートにInstrから先をMidで取ってくればOKです。
あとはここから検索文字列も消せばいいので、Midの開始位置を検索文字列の文字数分だけ増やせばいいということですね。
ある文字列より右側の部分 = Mid(元の文字列, InStr(元の文字列, 検索文字列) + Len(検索文字列))
1文字バージョンではRightがわかりやすい方も、2文字以上だとたぶんMidの方がわかりやすい気がします。
探す文字列が2回出てくる場合
探す文字列が2個ある場合は、最初の文字列を探すなら上記コードをそのまま使い、
最後の文字列を探すなら、Instr関数をInstrRev関数に置き換えます。
InstrRev関数は「右から探す」関数ですが、
見つけた位置はInstr関数と同じく「左から何文字目か?」を教えてくれます。
なので、関数を置き換える以外は、特別計算式を修正する必要はありません。
種類 = Right(商品名, Len(商品名) - InStrRev(商品名, 検索値) - Len(検索文字列) + 1) 種類 = Mid(商品名, InStrRev(商品名, 検索文字列) + Len(検索文字列))
さてこれで、指定の文字列より右側を取り出すコードの、
「Right/Mid/Instrを使った基本形」の解説は終了です。
続いて「Split関数の実践技」の解説に入ります。
Split関数を使う
冒頭で紹介した通り、今回のコードは↓の方法でも実装できます。
ある文字列より右側の部分 = Split(元の文字列, 検索文字列)(1) MsgBox Split("愛媛産みかん","産")(1) ' ← 「みかん」が表示されます。
Split関数で元の文字列を検索値を境に分割し、その最後の要素をとってくることでも、
目的の処理が果たせるということですね。
Split関数は配列を返す関数ですので、丁寧にコードを書いた場合は
商品名 = "愛媛産みかん" Dim 配列 配列 = Split(商品名, "産") ' この時点で「配列」は、0番に「愛媛」、1番に「みかん」が入っている 種類 = 配列(1) ' ←みかんを取ってこれる
こうなるのですが、Splitが返す配列を変数に入れずに直接参照すれば、
種類 = Split(商品名,"産")(1)
と、Split(~~)(1)のように書いてしまえるということです。
Split関数を「カンマとかコロンとかの区切り記号に使うもの」と考えていた人は、
「普通の文字列の検索にも使えるもの」と視野を広げてみましょう。
Split関数は「包丁でぶつ切り」するイメージが強いかもしれませんが、
「刀で真っ二つ」にするのにも非常に便利な関数です。
ただし、区切り文字がなかったときには、
作られる配列の要素が1個のため配列(1)が存在せず、
「インデックスが有効範囲にありません」エラーになってしまいます。
それを配列の状態で見分けようとすると
If Ubound(Split(商品名, "産")) > 0 Then 種類 = Split(商品名,"産")(1)
と、作られた配列の要素数が1個かどうか(=配列の添字の上限UBoundが0かどうか)で判定する必要がありますが、
こんな判定するくらいなら、
If InStr(商品名, "産") > 0 Then 種類 = Split(商品名,"産")(1)
と、Splitを使うかどうかの判定は結局Instrでやる方が読みやすくて綺麗です。
また、もう一つ大きな問題は、
「検索文字列が2個以上あって、Splitの結果3つ以上に分割される」
可能性があることです。
必ず検索文字列が2個あるとわかっていて、2個目から右を取るのであれば、
種類 = Split(商品名,"産")(2)
と、配列の添字を2にするだけでいいのですが、
「何個出てくるかわからないけど最後に出てきたやつの右側」をやるとなると、
種類 = Split(商品名,"産")(Ubound(Split(商品名,"産")))
と、配列の添字の上限UBoundを使って最終項を取ってくる羽目になります。
こんな式を書くくらいなら、
種類 = Mid(商品名, InStr(商品名, 検索値) + 1)
と、ちゃんと基本形で書いた方が読みやすいし短いですね。
ということで、どの方法も万能なんてことはなく一長一短です。
文字列操作の基本はやっぱりInstr関数だと思いますので、
基本の型としてInstrをマスターし、実践技としてSplitを身につけ、
どちらもしっかり扱えるようになるのが一番だと思います。
おまけ:文字列処理は関数化しておくと便利
今回のコードは特にそうなのですが、
文字列操作は頭がこんがらがってきやすく、コピペコードをいじるだけでも結構難しいので、
汎用関数にしておくと非常にコーディングが楽になります。
' 使用例(一度関数を作ればあとはこう書くだけでよくなる) MsgBox 右から文字列まで("和歌山県産みかん", "県産") ' ←みかんが表示されます。 ' 作る汎用関数 Function 右から文字列まで(ByVal 元の文字列 As String, 検索文字列 As String) As String Dim instr位置 As Long instr位置 = InStr(元の文字列, 検索文字列) If instr位置 > 0 Then 右から文字列まで = Mid(元の文字列, InStr(元の文字列, 検索文字列) + Len(検索文字列)) Else 右から文字列まで = "" End If End Function
使用例を見ればわかる通り、劇的に書きやすく、そして読みやすくなっていますよね?
一度作ってしまえばあとは使いまわすことができますし、
何なら自分で作らなくても、これをコピペすれば動きます。
私と共同開発したつもりになって、持って帰って使ってみてください。
関数と聞くと難しく感じるかもしれませんが、コードを見ればわかる通り、
中身は上で紹介したコードそのままです。
文字列操作は関数化が楽ちんで、その割に関数化の効果が大きいので、
関数づくりの練習にぴったりだと思います。
Functionプロシージャ勉強してみたいけど難しそうだな~って思っている方は、
ちょうどいいのでこの機会に始めて見るといいかもしれません。
今回の「右からある文字列まで」や、
他には「文字から文字までを取ってくる(例えばカッコの中身)」など、
私が作成した文字列操作の汎用関数集が下記のページにあります。
関数作成の参考にするなり、中身を見ないでコピーして使うなり、
ご自由にお持ち帰りください。