【VBA】InStr関数で文字列を検索する方法|文字位置・有無判定・大文字小文字(コピペOK)

【VBA】InStr関数で文字列を検索する方法|文字位置・有無判定・大文字小文字の解説用アイキャッチ画像 VBA
VBA InStr関数で文字列検索を安全に行う流れ
InStrは戻り値0の扱いを決めてから切り出し処理へ進むと安全です。

この記事でできること

セルや変数の文字列に「特定の文字が含まれているか」を一発で判定したい。あるいは「@マークの位置」を取って、その前後を切り出したい。VBAではInStr関数を使えば、わずか1行でこの2つを実現できる。本記事ではコピペでそのまま動くサンプルを使い、業務でつまずきやすい「戻り値0の判定ミス」「右から検索したいときのInStrRev」「Like・Replaceとの使い分け」までを実用本位で解説する。

これからVBAを学び始める方はVBA入門ロードマップもあわせてどうぞ。

Before / After:InStrは0判定がいちばん大事

VBA InStr関数で見つからない文字を0判定してから切り出すBefore After
InStrの戻り値をそのまま使わず、0かどうかを分岐してから切り出します。

自分は、同じ部署の人にマクロを配布したとき、相手のPC環境によってファイルパスの見え方や保存場所が少し違い、そこで苦労したことがあります。こういう環境差がある処理では、文字列の区切り位置を曖昧に扱うと、想定外のパスや入力値で止まりやすくなります。

InStrは「文字が見つかった位置」を返すだけの関数ですが、ファイルパス、メールアドレス、商品コード、ステータス文字列など、実務データの確認にかなりよく使えます。大切なのは、見つからなかったときの戻り値 0 を必ず受け止めることです。

この記事では、単なる関数説明ではなく、入力ミスや表記ゆれが混ざる前提で、どう安全に判定・切り出しするかを中心に整理します。

3秒で分かる結論

InStrは「対象文字列の中に検索文字が見つかった位置」を返す。見つからなければ0。判定するときは> 0を必ず付けるのが安全。

If InStr(対象文字列, 検索文字) > 0 Then
    ' 含まれていたときの処理
End If

業務サンプル①:メールアドレスから「@より前」を抽出する

顧客名簿のA列に並んだメールアドレスから、ローカル部(@より前)だけB列に取り出したいケース。たとえば「tanaka@example.com」→「tanaka」を抜き出す。

Sub ExtractLocalPart()
    Dim i As Long
    Dim lastRow As Long
    Dim atPos As Long
    Dim addr As String

    lastRow = Cells(Rows.Count, 1).End(xlUp).Row
    For i = 2 To lastRow
        addr = Cells(i, 1).Value
        atPos = InStr(addr, "@")
        If atPos > 0 Then
            Cells(i, 2).Value = Left(addr, atPos - 1)
        Else
            Cells(i, 2).Value = "(無効)"
        End If
    Next i
End Sub

ポイントはatPos > 0の判定。@がない不正な行を弾けるので、この後の処理が落ちなくなる。応用として「@より前を宛先キーにしてOutlookへ自動送信」も可能。詳細はExcelからOutlookメールを自動作成する方法を参照。

業務サンプル②:ファイルパスから拡張子と親フォルダを取り出す

「C:\Users\name\report.xlsx」のような絶対パスから、拡張子・ファイル名・親フォルダの3要素を取り出す。「右から検索したい」シーンなのでここではInStrRevを使う。

Sub SplitFilePath()
    Dim path As String
    Dim dotPos As Long
    Dim slashPos As Long

    path = "C:\Users\name\Documents\report.xlsx"

    ' 最後のドット位置 (拡張子の境目)
    dotPos = InStrRev(path, ".")
    ' 最後のバックスラッシュ位置 (フォルダの境目)
    slashPos = InStrRev(path, "\")

    Debug.Print "親フォルダ: " & Left(path, slashPos - 1)
    Debug.Print "ファイル名: " & Mid(path, slashPos + 1, dotPos - slashPos - 1)
    Debug.Print "拡張子   : " & Mid(path, dotPos + 1)
End Sub

結果は「親フォルダ: C:\Users\name\Documents」「ファイル名: report」「拡張子: xlsx」となる。サブフォルダ再帰検索でファイル一覧を取得する方法と組み合わせれば、フォルダ構造から特定の拡張子だけを抽出する処理が短時間で書ける。

引数の早見表

InStrの引数は最大4つ。省略可能な部分が多いので混乱しやすい。下表でまとめて把握してほしい。

引数意味省略時の値
start検索を開始する位置(先頭=1)1(先頭から)
string1検索される側の文字列必須
string2検索する文字列必須
compare比較モード(vbBinaryCompare / vbTextCompare)vbBinaryCompare(大小区別あり)

注意:startを指定するときはcompareも指定する必要がある。逆に、compareだけを指定したいときはstartに1を入れてInStr(1, s, t, vbTextCompare)と書く。

ハマりやすい罠:戻り値0を「> 0」で判定すること

InStrの戻り値は「見つかったら位置(1以上)、見つからなければ0」。VBAでは0はFalseと評価されるので、技術的にはIf InStr(s, t) Thenでも動いてしまう。だがこれは避けたい

悪い例(意図が読み取りにくい)

If InStr(addr, "@") Then
    ' "見つかったら処理する"つもりだが、
    ' 「数値の真偽判定なのか、位置を使いたいのか」が読み手に伝わらない
End If

良い例(意図が一目で分かる)

If InStr(addr, "@") > 0 Then
    ' "@が見つかった場合"だと一目瞭然
End If

後でコードを見返したとき、自分自身も他人も「あ、ここは含むかどうか判定してるんだな」とすぐ分かる。習慣として常に> 0を付けておくのが、メンテナンスしやすいコードへの第一歩だ。

InStrRev:右から検索したいとき

InStrは左から検索する。逆に「最後に出てくる位置」を取りたいときはInStrRev関数を使う。引数の順序が少し異なる点に注意。

Dim s As String
s = "C:\Users\Documents\report.xlsx"

Debug.Print InStr(s, "\")      ' → 3(最初の \ の位置)
Debug.Print InStrRev(s, "\")   ' → 19(最後の \ の位置)

パス処理・URL解析・拡張子抽出など「区切り文字の最後の位置」が知りたいシーンで頻出する。

大文字と小文字を区別したくないとき

InStrはデフォルトで大小を区別する(vbBinaryCompare)。「Abc」と「abc」は別物として扱われる。区別したくないときは第4引数にvbTextCompareを指定する(このとき第1引数startに1を入れる必要がある)。

Debug.Print InStr("Hello", "hello")                      ' → 0(区別あり)
Debug.Print InStr(1, "Hello", "hello", vbTextCompare)    ' → 1(区別なし)

顧客名やキーワード検索など、大小を意識しなくていいケースで重宝する。

VBA InStr InStrRev vbTextCompareの使い分け判断フロー
含む判定、切り出し、右から検索、大文字小文字の扱いで使う書き方を変えます。

InStr vs Like vs Replace 使い分け早見表

「文字列を扱う関数」は複数あって混乱しがち。やりたいことで早見表を用意した。

やりたいこと使う関数備考
含まれているか判定したいInStr (> 0)位置も同時に分かる
パターンで判定したい(例: 数字3桁+任意の文字)Like演算子ワイルドカード可。位置は取れない
含まれている文字を別の文字に置き換えたいReplace関数判定不要、変換だけする
位置を使って一部を切り出したいInStr + Left/Mid/Right本記事の業務サンプル①②
区切り文字で分割したいSplit関数結果は配列で返る

置換だけで足りるならセルの文字列を一括置換する方法が、区切り文字で分けたいなら文字列を区切り文字で分割して取り出す方法が効率的。

同じ文字が複数回出てくるときの全位置取得

InStrは「最初に見つかった位置」しか返さない。「すべての出現位置」を取りたいときは、Do Loopで前回の位置を引き継ぎながら繰り返す。

Sub FindAllPositions()
    Dim s As String
    Dim t As String
    Dim startPos As Long
    Dim foundPos As Long

    s = "apple,orange,banana,grape"
    t = ","
    startPos = 1

    Do
        foundPos = InStr(startPos, s, t)
        If foundPos = 0 Then Exit Do
        Debug.Print foundPos
        startPos = foundPos + 1
    Loop
End Sub

結果は6・13・20の3つの位置が出力される。なお区切り文字での分割ならSplit関数のほうが圧倒的にシンプルなので、用途に応じて選ぶといい。

実務でInStrを使うときの判断基準

InStrは短い関数ですが、実務ではファイル名、メールアドレス、商品コード、部署名、備考欄など、人が入力した文字列を判定する場面でよく使います。ここで大事なのは、検索したい文字が本当に固定なのか、表記ゆれがあり得るのかを先に決めておくことです。

たとえばファイルパスを判定するとき、PCの言語設定や保存場所の違いでフォルダー名が変わることがあります。同じ部署へマクロを渡したときも、自分の環境では通るパスが、相手のPCでは微妙に違うことがありました。その場合、パス全体を完全一致で見ようとするより、拡張子や末尾のフォルダー名など、変わりにくい部分をInStrで確認するほうが扱いやすいです。

判定前に確認すること

確認項目理由対処例
大文字小文字Excel、excel、EXCELのように表記が揺れるためvbTextCompareを使う
全角半角部署名や商品名で混ざることがあるため必要なら事前に表記をそろえる
検索対象が空白空欄に対して判定すると想定外になりやすいため先にLenで空欄チェックする
見つからない場合0のままMidやLeftに渡すと失敗しやすいためInStrの戻り値を変数に入れてから判定する
Dim pos As Long
pos = InStr(1, fileName, ".xlsx", vbTextCompare)

If pos > 0 Then
    MsgBox "Excelファイルです"
Else
    MsgBox "対象外です"
End If

ポイントは、InStrを条件式の中に直接書きすぎないことです。一度 pos のような変数に入れてから判定すると、見つかった位置を確認しやすく、見つからなかったときの処理も分けやすくなります。

FAQ

セルの値が数値のとき、InStrは使える?

InStrは文字列専用なので、セルの値が数値の場合はCStrで明示的に文字列に変換しておくと安全。詳しくは文字列⇔数値の型変換で計算エラーを防ぐ方法を参照。

空文字列を検索するとどうなる?

InStrの第3引数(検索文字)に空文字列””を渡すと、startで指定した位置(省略時は1)が返る。意図しない挙動になりやすいので、検索文字が空でないかは事前にチェックすると安全。

If Len(searchText) = 0 Then Exit Sub
foundPos = InStr(targetText, searchText)

含むセルをハイライトしたい

「特定の文字を含むセルを見つけて色付けする」業務直結サンプルは特定の文字を含むセルを検索してハイライトする方法に詳細がある。

ワイルドカードで判定したい

「先頭が”VB”で末尾が”A”」のようなパターン判定はLike演算子の出番。If addr Like "VB*A" Thenのように書ける。InStrよりも柔軟だが、位置は返さない。

まとめ

  • 含む判定はIf InStr(s, t) > 0 Thenが定石。> 0を省略しないのが鉄則
  • 右から検索したいときはInStrRev。パス解析・拡張子抽出に必須
  • 大小を無視したいときはInStr(1, s, t, vbTextCompare)
  • パターン判定はLike、置換はReplace、分割はSplitと使い分ける

関連記事

実務でミスしやすいInStrの使い方

InStrは便利ですが、実務では「見つかったかどうか」だけを見たい場面と、「見つかった位置を使って切り出す」場面が混ざりやすいです。まずは戻り値を変数に入れて、0かどうかを確認してから次の処理へ進めると、コードの意図が読みやすくなります。

やりたいこと使う判定注意点
文字が含まれるか調べるInStr(text, key) > 0= True のように書かず、位置が1以上かで判定します。
区切り文字の前後を切り出すpos = InStr(text, "@")pos = 0 のときに LeftMid を実行しないようにします。
後ろ側の区切りを探すInStrRev(path, "\")ファイルパスの最後のフォルダ区切りなどは、右から探すほうが安全です。

よくある失敗例:見つからない文字をそのまま切り出す

たとえばメールアドレスから「@より前」を取り出す処理で、@が入っていない値が混ざると Left(addr, atPos - 1) がエラーになります。業務データは空欄や入力ミスが混ざる前提で、次のように分岐を入れておくと安心です。

Sub ExtractLocalPartSafe()
    Dim addr As String
    Dim atPos As Long

    addr = Range("A2").Value
    atPos = InStr(1, addr, "@", vbTextCompare)

    If atPos > 1 Then
        Range("B2").Value = Left(addr, atPos - 1)
    Else
        Range("B2").Value = "メール形式を確認"
    End If
End Sub

大文字小文字を区別しない検索

商品コードやメールアドレスのドメインなど、人が入力する文字は大文字小文字が混ざりがちです。完全一致にこだわらない検索では、比較方法に vbTextCompare を指定します。

If InStr(1, Range("A2").Value, "urgent", vbTextCompare) > 0 Then
    Range("B2").Value = "要対応"
End If

InStrを使う前のチェックリスト

  • 検索対象が空欄でも処理が止まらないか確認する
  • 見つからなかった場合の戻り値 0 を必ず分岐で受ける
  • 大文字小文字を区別するか、vbBinaryComparevbTextCompare を決める
  • 後ろから探すほうが自然な場合は InStrRev を使う

InStrのFAQ

InStrとLikeはどちらを使うべき?

単純に「含まれているか」を見たいならInStrが読みやすいです。ワイルドカードを使って「Aで始まりBで終わる」のようなパターン判定をしたいときはLikeが向いています。

検索結果が0になるのはエラーですか?

エラーではありません。検索文字が見つからなかったという意味です。0を想定して分岐を書けば、入力ミスや空欄があっても処理を続けられます。

関連して覚えると便利な関数は?

文字列を分割するなら Split関数で文字列を分割する方法、型をそろえて判定したい場合は VBAの型変換、条件に応じて処理を止めたい場合は VBAのエラー処理 もあわせて確認すると実務コードが安定します。

コメント

タイトルとURLをコピーしました