読者です 読者をやめる 読者になる 読者になる

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

ネストされたカッコにも対応する

前回の記事が、この過疎ブログには珍しく反響があったので、ちょっと追加。

Replaceメソッドを使う方あり、Split関数を使う方あり、果ては正規表現を使うツワモノまで現れる始末……。

こうなったら、私も意地になって改良を加えますよー!

前回のコードの欠点

始めカッコがあったらスイッチオン、終わりカッコに出会ったらスイッチオフ、という単純なつくりなので、

f:id:akashi_keirin:20170410234627j:plain

たとえばこんなふうにカッコが設置されていたら、

f:id:akashi_keirin:20170410234635j:plain

途端に破綻……orz

そこで、少しだけコードに改良を加える。

改良したコード

リスト1
Sub deleteContents()
  Dim objCell As Range
  Dim objStr As String
  For Each objCell In Selection
    objStr = objCell.Value
    objCell.Value = _
      deleteContentsEnclosedByBracket _
                      (objStr, "(", ")")
  Next
End Sub

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

改良ポイントは、

カウンタ式フラグ n を導入した

こと。

まず、(1)のところ。

If chr = startBracket Then
  n = n + 1
  enableToDelete = True
End If

開始カッコと出会うたびに n をインクリメントする。

んで、(2)と(3)。

If chr = endBracket Then
  n = n - 1    '……(2)'
  If n = 0 Then    '……(3)'
    enableToDelete = False
    chr = ""
  End If
End if

終わりカッコに出会うたびに、逆に n をデクリメントする。これが(2)。

で、n が 0 になっていたら、削除可能フラグをOffにした上で、終わりカッコを""にする。

たとえば、対象文字列が ( (ち~んw) )! だったとすると、

  • Forループ1回目で「(」に出会うので、削除可能フラグenableToDeleteはTrue、n が1になる
    削除フラグOnなので、「(」はtmpには追加されない→消されたように見える
  • Forループ2回目で「(」に出会うので、削除可能フラグenableToDeleteはTrue、n が2になる
    削除フラグOnなので、「(」はtmpには追加されない→消されたように見える
  • Forループ3回目
    削除可能フラグenableToDeleteがTrueなので「ち」はtmpに追加されない→消されたように見える
  • Forループ4回目
    削除可能フラグenableToDeleteがTrueなので「~」はtmpに追加されない→消されたように見える
  • Forループ5回目
    削除可能フラグenableToDeleteがTrueなので「ん」はtmpに追加されない→消されたように見える
  • Forループ6回目
    削除可能フラグenableToDeleteがTrueなので「w」はtmpに追加されない→消されたように見える
  • Forループ7回目で「)」に出会うのが、n が1になるだけなので、削除可能フラグenableToDeleteはTrueのまま
    削除可能フラグenableToDeleteがTrueなので「)」はtmpに追加されない→消されたように見える
  • Forループ8回目で「)」に出会い、今度は n が 0 になるので、削除可能フラグenableToDeleteがFalseになる
    削除フラグOffになるが、「)」は""になるのでtmpには追加されない→消されたように見える
  • Forループ9回目、enableToDeleteはFalseになっているので、「!」はtmpに追加される

という流れで、カッコ内の文字列が除去され、「!」だけが残ることになる。

実行結果

f:id:akashi_keirin:20170410234627j:plain

この状態で実行すると、

f:id:akashi_keirin:20170410234643j:plain

ほれ、この通り。カッコがネストされていても望む結果が得られた。

おわりに

コレ、むきになって更新するようなことなのかね……???

@akashi_keirin on Twitter