和風スパゲティのレシピ

日本語でコーディングするExcelVBA

ある文字列からある文字列までを取り出す

テキストから2つの文字列を検索し、
その間にある文字列を取得する方法を解説します。

ある「文字」からある「文字」までを取り出す場合

基本の書き方

開始位置 =  InStr(元の文字列, 文字A) + 1
終了位置 =  InStr(元の文字列, 文字B) - 1

文字Aから文字Bまで = Mid(元の文字列, 開始位置, 終了位置 - 開始位置 + 1)

実行サンプル

Dim 商品名 As String, 産地 As String
Dim 開始 As Long, 終了 As Long

商品名 = "みかん(和歌山産)"
開始 = Instr(商品名, "(") + 1
終了 = Instr(商品名, ")") - 1

産地 = Mid(商品名, 開始, 終了 - 開始 + 1)

MsgBox 産地 ' ← 「和歌山産」が表示されます。

解説

じっくりコードを読んだ方がわかりやすいかもしれませんが一応説明を。


まずはInstr関数でカッコの位置から開始と終了を求め、それを
Mid関数(元の文字列, 開始位置, 取ってくる文字数)
に代入しています。

取ってくる文字数は、終了位置 - 開始位置 + 1で計算できますね。


もし「(和歌山産)」と、検索文字も一緒に持って来たい場合は、

開始 =  InStr(元の文字列, 文字A)
終了 =  InStr(元の文字列, 文字B)

と、開始と終了の「±1」を消せばOKです。


コード中にたくさん変数を作りましたが、変数を使わない場合は、

文字Aから文字Bまで = Mid(元の文字列, InStr(元の文字列, 文字A) + 1, InStr(元の文字列, 文字B) - InStr(元の文字列, 文字A) - 1)

になってしまい、訳が分からなくなります。


特に「開始の+1」「終了の-1」「文字数の+1」の「1」トリオが、
合体して「-1」になるところを頭の中でやると大抵バグを書きます
からね。


変数にしておけば、読みやすく、ミスも少なくなりますし、
あとでどちらかの文字がなかった場合の分岐を作るときにも使えます。


今回のような面倒な文字列処理をする場合は、
なるべく丁寧に変数を作っておきましょう。

マクロは書く時間より読む時間の方が実は長いので、
サボらず変数にしておくとマクロが仕上がるのも早くなりますよ。


ちなみに、このようなコードに名前を付けて読みやすくするための変数のことを、
「説明変数」と呼びます。

i = i + 1 みたいに値を推移させていく「カウンタ変数」や、
処理シートのオブジェクトを格納する変数など、処理に必須の変数と違い、
「無くても処理は書けるけどあると読みやすい」変数のことですね。


説明変数の目的は当然「説明」であり、コードに直接書けるコメントとも言えます。

変数名が普段英語の方も、「説明変数」だけは母国語で書くことをおすすめします。

同じ文字を検索したり、文字の出てくる順番を指定する場合

少し癖のある文字列で、

みかん_和歌山産_ から「_」の間を取ってきたり、
1) みかん(和歌山産) の最初の)は無視して()の中が欲しいことがあります。


この処理を書くのは意外と簡単で、

開始 = Instr(商品名, "_")
終了 = Instr(開始 + 1, 商品名, "_") ' ← 1つめのアンダーバーの発見位置より右を検索

開始 = Instr(商品名, "(")
終了 = Instr(開始 + 1, 商品名, ")") ' ← ( が見つかった場所より後の ) を検索

と、終了位置を検索するInstr関数の「どこから探し始めるか」である第1引数に、
開始位置の次の文字(+1)を指定してあげればOK
です。


結構忘れがちですが、Instr関数の第1引数は「どこから探し始めるか」です。


最初の引数に数字ではなく文字列を渡すと、

「あ、これは開始位置を省略したんだな」

と、第2引数にその文字列を渡してくれるので、なかなか気が利く関数さんですね。


ある「文字列」からある「文字列」までを取り出す場合

続いて探す文字が2文字以上になる場合のコードです。

開始位置 =  InStr(元の文字列, 文字列A) + Len(文字列A)
終了位置 =  InStr(元の文字列, 文字列B) - 1

文字列Aから文字列Bまで = Mid(元の文字列, 開始位置, 終了位置 - 開始位置 + 1)

終了位置に変更はありませんので、開始位置を探す文字列の長さだけズラします。
最後のMid関数式にも当然変更はありません。


簡単に感じるのは最後のMid関数式を代入で済ませてくれる説明変数のおかげであり、
これを1発でやろうとすると大変なことになりますのでご注意ください↓

文字列Aから文字列Bまで = Mid(元の文字列, InStr(元の文字列, 文字A) + Len(文字列A), InStr(元の文字列, 文字B) - InStr(元の文字列, 文字A) - Len(文字列A) - 1)

別解:文字列を少しずつ加工していくパターン

今までのコードは「最後にMid関数に渡す材料を作る」方式でした。

別パターンとして、「少しずつ文字列を加工していく」方式で書くとこうなります。

商品名 = "みかん(和歌山産)"
産地 = Left(商品名, Instr(商品名, ")") - 1)
産地 = Mid(産地, Instr(産地, "(") + 1)

MsgBox 産地 ' ← 「和歌山産」が表示されます。

まずは")"より右側を削除して、
次に"("より左側を削除しています。


変数の中身がちょっとずつ変わっていく処理は、
1行ごとに独立したコードでない = 処理全体追わないと読めない
という弱点があるため、あまり乱用はしない方がいいと思います。

↑のコードは1行だけで動かせるコードがないですからね。


ただ、この方法の方がきれいに書けるときもありますので、
引き出しとして持っておく価値はあると思います。

心の片隅にでも置いておいてください。

おまけ:文字列処理は関数化しておくと便利

今回の「ある文字列からある文字列まで」は、

文字列Aから文字列Bまで = Mid(元の文字列, InStr(元の文字列, 文字A) + Len(文字列A), InStr(元の文字列, 文字B) - InStr(元の文字列, 文字A) - Len(文字列A) - 1)

こんなコードになるので1行では書けません。


しかし、説明関数があるとわかりやすくなるとはいえ、

Dim 商品名 As String, 産地 As String
Dim 開始 As Long, 終了 As Long
商品名 = "みかん(和歌山産)"
開始 = Instr(商品名, "(") + 1
終了 = Instr(商品名, ")") - 1
産地 = Mid(商品名, 開始, 終了 - 開始 + 1)

こっちはこっちで行数を消費してしまうので、マクロ全体が長くなるとそれはそれで読みづらくなります。


ということで、文字列処理を多くやる人は、↓のように汎用関数を作ってみましょう。

' 目的:汎用関数を作って↑のコードをこう書けるようにしたい
産地 = 文字列から文字列まで(商品名, "(", ")")

' 用意する汎用関数
Function 文字列から文字列まで(ByVal 元の文字列 As String, 前方文字列 As String, 後方文字列 As String) As String

    Dim 開始 As Long, 終了 As Long
    開始 = Instr(元の文字列, 前方文字列) + Len(前方文字列)
    終了 = Instr(元の文字列, 後方文字列) - 1
    If 開始 = 1 Or 終了 = -1 Then Exit Function ' どちらかの文字がなければ""を返す

   文字列から文字列まで = Mid(元の文字列, 開始, 終了 - 開始 + 1)

End Function

' 使用例
MsgBox 文字列から文字列まで("みかん(和歌山産)", "(", ")") ' ←和歌山産が表示されます。

これで1行で処理できるうえに、処理の内容が読めるようになります。


一度作ってしまえばあとは使いまわすことができますし、
何なら自分で作らなくても、これをコピペしても動きます。

私と共同開発したつもりになって、持って帰って使ってみてください。


関数と聞くと難しく感じるかもしれませんが、コードを見ればわかる通り、
中身は上で紹介したコードそのままです。

文字列操作は関数化が楽ちんで、その割に関数化の効果が大きいので、
関数づくりの練習にぴったりだと思います。


Functionプロシージャ勉強してみたいけど難しそうだな~って思っている方は、
ちょうどいいのでこの機会に始めて見るといいかもしれません。


今回の「文字列から文字列までを取ってくる」など、
私が作成した文字列操作の汎用関数集が下記のページにあります。

関数作成の参考にするなり、中身を見ないでコピーして使うなり、
ご自由にお持ち帰りください。

www.limecode.jp