文字列のカッコで括られた部分だけを狙い撃ちで削除するマクロ

セル内のカッコで括られた文字列のみ削除する

都道府県番号の一覧表

ひょんなことで、都道府県番号の一覧表が欲しいなあと思ってggってみたら、

f:id:akashi_keirin:20170409102348j:plain

こんな一覧ばっかり(画像はWikipediaのものです)で、表形式のまま取り込めるものがなかなか見つからなかった。

やっとのことで、

f:id:akashi_keirin:20170409102403j:plain

こんなページを見つけて、Excelの表に貼り付けたんだが、

f:id:akashi_keirin:20170409102426j:plain



カッコの中の読み仮名がジャマ!!!!!!!!

なんですよねー。

まあ、しょせん47都道府県のことだから、手作業でやっても大して時間はかからないわけなんですが、マクロでやりましたよ。

カッコで括られた部分のみ削除するマクロ

今回は、次のような感じで組み立ててみました。

処理の流れ
  • 文字列の文字数を取得して文字数分ループ
  • 文字列の先頭から1文字づつ調べる
  • 開始カッコのところまでは順に連結
  • 開始カッコのところに来たら削除フラグOn
    削除フラグがOnの間は文字を連結しない
  • 終了カッコのところまで来たら削除フラグOff
    削除フラグOffの間は文字を連結する
  • できあがった文字列をセルに返す

これを、For Each ~ In Selectionで回す、というちょい書きマクロ。

リスト1-1

まずは、メインのコード。

Sub deleteContents()
  Dim objCell As Range
  Dim objStr As String
  For Each objCell In Selection    '……(1)'
    objStr = objCell.Value    '……(2)'
    objCell.Value = _
      deleteContentsEnclosedByBracket _
                      (objStr, "(", ")")    '……(3)'
  Next
End Sub
コードの説明

(1)の

For Each objCell In Selection
  '処理の内容
Next

は、選択範囲の各セルに処理を施すというやつで、今回のようなちょい書きマクロでは非常によく使う方式(って、私だけ……?)。

処理を施す範囲を柔軟に設定できるので、重宝している。

(2)の

objStr = objCell.Value

では、一旦変数にセルの中身をセット。

んで、(3)では、自作のdeleteContentsEnclosedByBracket関数(ってか、長ぇ名前だな、オイ!)に文字列を渡して「カッコでくくった文字列を削除する」処理をさせている。

別に、この程度の処理なので外に括り出すまでもなかったかも知れないけれど、もしかしたらあとあと拡張できるかもしれないと思ったので、今回もYAGNYの原則に反する対応をとってしまった……orz

まあ、Forループがネストするのはできれば避けたいというのもある。

リスト1-2

コチラは、呼び出されるdeleteContentsEnclosedByBracket関数のコード。

Private Function deleteContentsEnclosedByBracket _
                  (ByVal objStr As String, _
                   ByVal startBracket As String, _
                   ByVal endBracket As String) As String    '……(1)'
  Dim enableToDelete As Boolean    '……(2)'
  Dim tmp As String
  Dim chr As String
  Dim i As Integer
  For i = 1 To Len(objStr)    '……(3)'
    chr = Mid(objStr, i, 1)    '……(4)'
    If chr = startBracket Then    '……(5)'
      enableToDelete = True
    End If
    If chr = endBracket Then    '……(6)'
      enableToDelete = False
      chr = ""    '……(*)'
    End If
    If enableToDelete = False Then    '……(7)'
      tmp = tmp & chr
    End If
    If enableToDelete = True Then    '……(8)'
    End If
  Next
  deleteContentsEnclosedByBracket = tmp    '……(9)'
End Function
リスト1-2の説明

まず、(1)。

Private Function deleteContentsEnclosedByBracket _
                  (ByVal objStr As String, _
                   ByVal startBracket As String, _
                   ByVal endBracket As String) As String

第1引数のobjStrが、処理対象の文字列。

第2引数のstartBracketは、開始カッコ。

第3引数のendBracketは、終了カッコ。

引数名がやたら長いのはいつものことなんですが、意味の取れる引数名にしようとするとどうしてもこうなっちゃうんですよねー。

要するに、第1引数で渡された文字列に対して、第2・3引数で渡された文字で括られた文字列を削除して返す、という処理をするわけです。

当然、第2引数や第3引数に2文字以上の文字列を渡されたら困るわけですが、ちょい書きなので……。

(2)からの4行

Dim enableToDelete As Boolean
Dim tmp As String
Dim chr As String
Dim i As Integer

は変数の宣言。いちおう、

  • enableToDelete……削除可能フラグ
  • tmp……一時的に文字列を入れておく
  • chr……処理対象文字列から取り出した1文字を入れておく
  • i……Forループ用のカウンタ

といったところ。

(3)では、

For i = 1 To Len(objStr)
  '処理の内容
Next

の形で受け取った文字列の文字数分ループ処理を行う。Len関数は、

Len(文字列

の形で文字列の文字数を返してくれる。

(4)では、

chr = Mid(objStr, i, 1)

Mid関数を用いて、objStrで渡した文字列の中からi番目1文字を変数chrにセットしている。

Mid関数は、

Mid(文字列,開始位置,切り出したい文字数)

の形で、文字列の[開始位置]番目から[切り出したい文字数]文字分の文字列を返してくれる。

んで、(5)と(6)では、

If chr = startBracket Then
  enableToDelete = True
End If
If chr = endBracket Then
  enableToDelete = False
  chr = ""    '……(*)
End If

切り出した1文字が開始カッコまたは終了カッコかどうかを判定して、削除可能フラグのOn / Offを切り替えるようにしている。Elseを使えば行数を減らせるのは分かっていますが、最近は極力Elseを使わないようにしているので。

ちなみに、(*)を忘れると、けったいな結果になるので注意。当たり前ですが。

(7)の

If enableToDelete = False Then
  tmp = tmp & chr
End If

は、削除可能フラグがOffの場合の処理。普通に切り出した1文字を追加しているだけ。

(8)の

If enableToDelete = True Then
End If

は、別にいらないんだけど、あえて書いている。削除可能フラグOnのときは何もしない、ということ。

削除可能フラグOnの間に出てくる文字列は削除対象なので、追加しない、という形で削除を実現。

で、(9)。

deleteContentsEnclosedByBracket = tmp

Forループを抜けたということは、全文字に対する処理が終わったということだから、できあがった文字列tmpを呼び出し元に戻り値として返してやる。

実行結果

f:id:akashi_keirin:20170409102452j:plain

範囲を選択して実行すると、

f:id:akashi_keirin:20170409102500j:plain

ほれ。カッコで括られていた文字列が消えた。

おわりに

こういうちょっとした処理がサクサクっと書けるようになると、Excelを使った作業系の仕事は激速になると思う。

@akashi_keirin on Twitter