和風スパゲティのレシピ

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

カッコ内の文字列を取得する関数-Mid,Instr関数

文字列から "(" と ")" を検索し、カッコの中身を取得する方法を解説します。

基本のコード

例えば「みかん(和歌山産)」から「和歌山産」を取得する場合は、
以下のコードを実行します。

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

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

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

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

まずはInstr関数で「開きカッコ」を検索し、その次の文字を開始位置に、
続いてInstr関数で「閉じカッコ」を検索し、その前の文字を終了位置に、

そうして求まった「○文字目から△文字目」という位置情報を、
Mid関数(元の文字列, ○, △ - ○ + 1)
に代入しています。


Mid関数は終了位置ではなく文字数を指定する必要がありますので、
終了位置 - 開始位置 + 1で文字数を計算しています。


変数が多くて面倒な気がしてしまうかもしれませんが、
変数を用意しない場合は、

Mid("みかん(和歌山産)", InStr("みかん(和歌山産)", "(") + 1, InStr("みかん(和歌山産)", ")") - InStr("みかん(和歌山産)", "(") - 1)

こうなります。

確かに1行で済んではいますが、書き上げるのにかかる時間を計測したら、
間違いなく変数を用意した方が短くなると思います。

全角カッコを半角カッコに戻してから位置を取得する

基本形のコードは上記の通りですが、残念ながら実務ではそう上手くはいきません。

カッコは基本的に全角と半角が入り乱れているものですからね。


これに対処するのは意外と簡単で、

商品名 = Replace(商品名, "(", "(")
商品名 = Replace(商品名, ")", ")")
開始 = Instr(商品名, "(") + 1
終了 = Instr(商品名, ")") - 1

と、Replace関数を使ってカッコを半角に統一してから、
開始・終了位置の取得に入ればOKです。


こういったカスタマイズを後から行うときも、
変数に入れて読みやすくしておくのはとても大切です。


未来の自分への贈り物だと思って、サボらず変数を作っておきましょう。

複数のセルへ実行するコード

例えば、

商品名 産地
みかん(和歌山産)      
りんご(青森産)      
     

このような表で、B列の産地を取得するコードは以下のように書きます。

Sub A列の商品名からB列の産地を取得する()
    Application.ScreenUpdating = False

    Dim R As Long
    Dim LastR As Long
    LastR = ActiveSheet.UsedRange.Rows.Count + ActiveSheet.UsedRange.Row - 1
    
    ' 商品名のある全データをループ
    For R = 2 To LastR
        If Cells(R, 1) <> "" Then

            ' カッコを半角にしてから位置を検索
            Dim 商品名 As String, 開始 As Long, 終了 As Long
            商品名 = Cells(R, 1)
            商品名 = Replace(商品名, "(", "(")
            商品名 = Replace(商品名, ")", ")")
            開始 = InStr(商品名, "(") + 1
            終了 = InStr(商品名, ")") - 1
            
            ' どちらのカッコもあり、(よりも)が後ろにあれば産地を取得
            If 開始 > 1 And 終了 >= 開始 Then
                Cells(R, 2) = Mid(商品名, 開始, 終了 - 開始 + 1)
                Cells(R, 1) = 商品名 ' ←ついでにカッコの表記ゆれも直す
            End If
    
        End If
    Next ' 商品名のある全データをループ
    
End Sub

メインの「カッコの中身」取得コードは基本形そのままですね。


メインコードの実行前に、

If 開始 > 1 And 終了 >= 開始 Then

この判定を入れておくことで、Mid関数がエラーで止まることを防いでいます。


データエリア全体に処理をする場合は、
このようにFor~Nextループ内でカッコ内取得コードを使ってください。

おまけ:カッコ内を取得する自作関数を作る

カッコ内の文字を取得する処理をよく行う方は、
その処理を関数として自作しておくと非常に便利です。

上記のマクロを、自作関数を使って書くとこんな感じになります↓

Sub A列の商品名からB列の産地を取得する()
    Application.ScreenUpdating = False

    Dim R As Long
    For R = 2 To Get最終行(ActiveSheet)
        If Cells(R, 1) <> "" Then
            Cells(R, 2) = Getカッコ内(Cells(R, 1))
        End If
    Next
    
End Sub

' テキストのカッコ内を取得する
Function Getカッコ内(ByVal 元テキスト As String) As String
    
    元テキスト = Replace(元テキスト, "(", "(")
    元テキスト = Replace(元テキスト, ")", ")")

    Dim 開始 As Long, 終了 As Long
    開始 = InStr(元テキスト, "(") + 1
    終了 = InStr(元テキスト, ")") - 1
    
    If 開始 > 1 And 終了 >= 開始 Then
        Getカッコ内 = Mid(元テキスト, 開始, 終了 - 開始 + 1)
    End If

End Function

' シートの最終行を取得する
Function Get最終行(ws As Worksheet) As Long
    Get最終行 = ws.UsedRange.Rows.Count + ws.UsedRange.Row - 1
End Function

メインマクロが尋常じゃないほど短くなっていますね。

しかも「Getカッコ内」と、ノーコメントで読めるようになっているおまけつき!


関数を自作するメリットは、実は「使いまわせる」というメリット以上に、
処理を1行にして名前を付けられる」メリットの方が重要だったりします。

その効果はこのコードを見れば一目瞭然ですね。


その上でもちろん「使いまわせる」というのも重要で、
この関数は別のマクロでも使えますので、じゃんじゃん使いまわしてください。


自作関数といいながら作成者は私ですが、
これをコピペして持っていけばそのまま使えます。

しれっと関数化した「シートの入力最終行の取得」もお土産にどうぞ。


関数化に興味がわいた方は、ぜひこちらの記事もご覧ください。

www.limecode.jp



最後に小ネタを少々。

関数を自作するメリットは、実は「使いまわせる」というメリット以上に、
処理を1行にして名前を付けられる」メリットの方が重要だったりします。

↑この件ですが、
 

Dim R As Long
For R = 2 To GetLastRow(ActiveSheet)
    If Cells(R, 1) <> "" Then
        Cells(R, 2) = GetStrInParentheses(Cells(R, 1))
    End If
Next

↑このコードは、そのメリットを享受できていますでしょうか?


今回の例のように、「関数の作り方」を学ぶとなると、
Functionプロシージャの構文を覚えるといったシステム的な勉強よりも、
文章力や読解力をプログラミングに活かす勉強が必要になります。


それを母国語を使わずに修練しようとすると、
無駄に苦労するだけでちゃんとした設計力が身に付きません。



ある程度実力が付いた後、変数・関数を英語にするかどうかは自由です。


ですが少なくとも「関数の作り方」を学んでいる段階では、
格好つけずにちゃんと母国語を頼りましょう。
 
www.limecode.jp