InStr関数で文字列の位置を先頭から調べる

今回の目標

「文字列を先頭から検索したい!」や「InStr関数とInstrRev関数は何が違うの?」と疑問を持ったあなたへ。
この記事では、InStr関数の使い方から、InstrRev関数の違いを、まとめて丁寧に解説します! 基本的なだけでなく、実務で使える具体例つきです。

目標リスト

  • InStr関数について、理解する
  • InStr関数とInstrRev関数の違いを理解する

InStr関数について

InStr関数とは

InStr関数は、文字列内で特定の文字列が先頭から数えて何番目にあるかを返します。 もし、文字列の中に調べたい文字が含まれていなかった場合は、数字の「0」を返します。
文字「ABCABC」で、文字「A」をInStr関数を使用すると、「1」が返ります。
例えば、メールアドレスの「@」までの位置(ローカル部)と「@」より後(ドメイン部)を分ける場合に使用します。

InStr関数の引数一覧と戻り値

InStr関数の構文

InStr(start, string1, string2, compare)

InStr関数の引数一覧

InStr関数の構文と引数一覧です。

※一部、Microsoft社のリファレンスを参照しています。
 【Microsoft公式】 InStr 関数

名前省略規定値説明
start可能1何文字目から検索するか(検索開始位置)
string1不可-検索する文字列(検索文字)
string2不可-検索対象の文字列(被検索文字)
compare可能vbBinaryCompare大文字・小文字、全角・半角が違っても置換をするか。規定値の場合、文字種が違うと、検索対象にならない。

引数「compare」の定数一覧です(実用的な定数のみ記載します)。

名前説明
vbBinaryCompare0大文字・小文字、全角・半角が異なる場合、検索対象としない
vbTextCompare1大文字・小文字、全角・半角が異なる場合、検索対象とする

使用サンプル

1.メールアドレスの「@」の位置を取得する

メールアドレスの「@」の位置を取得します。
今回は他関数との連携例として、「@」より前(ローカル部)及び、「@」より後ろ(ドメイン部)も取得します。 ローカル部はLeft関数、ドメイン部はMid関数で取得すると良いでしょう。

サンプルコード

Sub SampleInStr1()
    Dim mailAddress As String
    Dim mailLocal As String
    Dim mailDomain As String
    Dim sepPos As Long
    
    mailAddress = "hogefuga@example.com"
    
    '@ が何文字目か取得する
    sepPos = InStr(mailAddress, "@")
    ' ローカル部を抽出する
    mailLocal = Left(mailAddress, sepPos - 1)
    ' ドメイン部を抽出する
    mailDomain = Mid(mailAddress, sepPos + 1)
    ' イミディエイトウィンドウ(Ctrl + G)に表示
    Debug.Print "メールアドレス:" & mailAddress
    Debug.Print "@ が何文字目か:" & sepPos
    Debug.Print "ローカル部  :" & mailLocal
    Debug.Print "ドメイン部  :" & mailDomain
End Sub
【実行結果】

メールアドレス:hogefuga@example.com
@ が何文字目か:9
ローカル部  :hogefuga
ドメイン部  :example.com

2.スペース区切りのデータを切り分ける

スペース区切りやカンマ区切り等でデータを分けている場合、その位置が分かります。
次のサンプルコードは、ファーストネームを取得します。

サンプルコード

Sub SampleInStr2()
    Dim fullName As String
    Dim firstName As String
    Dim sepPos As Long
    
    ' John Michael Smith(ジョン・マイケル・スミス)
    fullName = "John Michael Smith"
    
    ' 最初のスペースの位置を取得する
    sepPos = InStr(fullName, " ")
    ' ファーストネームを抽出する
    firstName = Left(fullName, sepPos - 1)
    ' イミディエイトウィンドウ(Ctrl + G)に表示
    Debug.Print "本名:" & fullName
    Debug.Print "スペースが何文字目か:" & sepPos
    Debug.Print "ファーストネーム  :" & firstName
End Sub
【実行結果】

本名:John Michael Smith
スペースが何文字目か:5
ファーストネーム  :John

3.ファイル名で使用できない文字がないか確認する

Windowsの場合、ファイル名として使用できない文字が複数あります。
これが、文字列中に含まれていないかを確認できます。

サンプルコード

Sub SampleInStr3()
    Dim arr() As Variant
    Dim var As Variant
    Dim invalStr As String   'inval = invalid
    Dim fileName As String
    
    fileName = "abc/>.txt"
    'Windowsの場合
    arr = Array("\", "/", ":", "*", "?", """", "<", ">", "|")
    
    For Each var In arr
        If 0 < InStr(fileName, var) Then
            'ファイル名に含まれてる「使用できない文字」を記録する
            invalStr = IIf(invalStr <> "", invalStr & ",", "") & var
        End If
    Next var
    
    If invalStr <> "" Then
        Debug.Print "文字【" & invalStr & "】が含まれています!"
    Else
        Debug.Print "ファイル名として使用できます!"
    End If
End Sub
【実行結果】

文字【/,>】が含まれています!

4.大文字小文字や、全角半角を区別せずに位置を取得する

InStr関数は、文字列と検索する文字の大文字・小文字や全角・半角が異なると位置を取得できません。 しかし、InStr関数の第4引数に「vbTextCompare」を指定することで、大文字小文字および全角半角の違いを無視して、位置を取得できます。
なお、第4引数を指定する場合は、第1引数を省略できません。

サンプルコード

Sub SampleInStr4()
    Dim str As String
    Dim posBinaryCompare As Long
    Dim posTextCompare As Long
    
    str = "abcabc"
    posBinaryCompare = InStr(str, "B")
    posTextCompare = InStr(1, str, "B", vbTextCompare)
    
    Debug.Print "posBinaryCompare:" & posBinaryCompare
    Debug.Print "posTextCompare:" & posTextCompare
End Sub
【実行結果】

posBinaryCompare:0
posTextCompare:2

5. 2回目以降の特定の文字列の位置を取得する

InStr関数の第1引数は「何文字目から検索を開始するか」です。
例えば、文字「ABAB」から、文字「B」の2回目が何文字目にあるかを調べたい場合、1回目のBが何文字目にあるかを調べ、最初に見つかった位置の直後から再度検索することで2回目の文字「B」の位置を取得できます。

サンプルコード

Sub SampleInStr5_1()
    Dim str As String
    Dim search As String
    Dim pos As Long
    
    search = "c"
    str = "abcabcabcabc"
    
    '1回目の位置
    pos = InStr(str, search)
    '2回目の位置
    pos = InStr(pos + 1, str, search)
    
    Debug.Print "2回目の 'c' の位置:" & pos & "文字目"
End Sub
【実行結果】

2回目の 'c' の位置:6文字目

検索文字が3回目以降の場合

例えば、文字「abababab」において、「b」の3回目の位置を取得したいとします。
先とサンプルの様に、InStr関数をステップごとに記載するとプログラムが長くなってしまいます。 その場合は、For文を用いることでコードを簡潔にできます。

サンプルコード

Sub SampleInStr5_2()
    Dim str As String
    Dim search As String
    Dim show As String
    Dim i As Long
    Dim num As Long  '何回目、検索するか
    Dim pos As Long
    
    search = "c"
    num = 3     '「3」回目の文字cの位置を検索する
    str = "abcabcabcabc"
    
    '文字を検索する
    For i = 1 To num
        pos = InStr(pos + 1, str, search)
    Next i
    
    If 0 < pos Then
        show = num & "回目の文字" & search & "は" & pos & "文字目にあります。"
    Else
        show = "文字" & search & "は、文字列中に" & num & "個、存在しません。"
    End If
    
    Debug.Print show
End Sub
【実行結果】

3回目の文字cは9文字目にあります。

InStr関数とInstrRev関数の違いと使い分け

機能などの違いについて

関数名について

関数名の表記に違いがあります。
InStr関数は『S』が大文字ですが、InstrRev関数は『s』が小文字です。

関数の機能の違いについて

先頭から検索する関数は、本記事で紹介した「InStr関数」です。
末尾から検索する関数は、「InstrRev関数」です。

引数の位置について

InStr関数と、InstrRev関数 で引数のデータ自体は同じですが、順番が異なります。

  • InStr関数何文字目から検索するか, 被検索文字, 検索文字, 比較種類)
  • InstrRev関数(被検索文字, 検索文字, 何文字目から検索するか, 比較種類)

上記の通り、「何文字目から検索するか(検索開始位置)」の位置が異なります。

InStr関数とInstrRev関数の使い分け

特定の文字が含まれているかどうかを確認するだけであれば、どちらの関数を使っても同じ結果が得られます。
それに対し、フルパスからファイル名を取得する、などの取得する位置が重要な場合は使い分けが必要です。

  • InStr関数
    ・外国人のファーストネームを取得する
     ※ ファーストネーム、ミドルネーム、ラストネームがあるときに有用
    ・電話番号の市外局番を取得する
  • InstrRev関数
    ・フルパスからファイル名を取得する
    ・拡張子を取得する

注意点(戻り値、InstrRev関数との動作の違い等)

InStr関数の注意点は以下の通りです。
赤の太字は、InstrRev関数と挙動が異なるので注意しましょう。

被検索文字について

  • 被検索文字が空文字("")の場合、『0』を返す
  • 被検索文字が「Null」の場合、『Null』を返す
  • 被検索文字が「Nothing」の場合、実行時エラー91が発生する

検索文字について

  • 検索文字が空文字("")の場合、検索開始位置を返す
  • 検索文字が「Null」の場合、『Null』を返す
  • 検索文字が「Nothing」の場合、実行時エラー91が発生する

検索開始位置について

  • 検索開始位置が被検索文字の長さより長いと、『0』を返す。
    ただし、検索文字が空文字("")の場合、検索開始位置を返す。
    ※ InstrRev関数は、検索文字が空文字("")の場合でも、『0』を返す。
  • 検索開始位置が「0」以下の場合、実行時エラー5が発生する。
    ただし、被検索文字か、検索文字が空文字("")の場合、『0』を返す。
  • 検索開始位置が小数の場合、CInt関数の丸めの変換が行われる。
    例)2.50 → 2、 2.51 → 3、 3.5 → 4、 4.5 → 4

発生する可能性があるエラーについて

実行時エラー5
プロシージャの呼び出し、または引数が不正です。

実行時エラー91
オブジェクト変数または With ブロック変数が設定されていません。

実行時エラー94
Null の使い方が不正です。

関連リンク

ページの先頭へ