以下の内容はhttps://www.limecode.jp/entry/fungo/replace-it-with-dxより取得しました。


72本目:ITをDXに変換(文字列操作)

Excel&VBA解説サイト「エクセルの神髄」様出題の問題集、
VBA100本ノック」に対する私の回答と解説のページです。

100本ノックの出題リストはこちらから
excel-ubara.com

出題:ITをDXに変換(文字列操作)

#VBA100本ノック 72本目
引数の文字列に以下の処理を行い文字列で返すFunctionを作成。
全ての"IT"を"DX"に置換
※大小文字全半角問わず
※直前または直後がアルファベットの場合は対象外
※空白及び'は除いて判定
置換する:"IT","と IT","itは","IT 99"
しない:"GIT","site","It's","it is"

ITをDXに置換

◇ 出題ページはこちら

ソースコード

Option Explicit

' 100本ノック072:ITをDXに変換(文字列操作)
Function ReplaceIT→DX(str元文字列 As String) As String

    Dim str結果値 As String: str結果値 = str元文字列

    ' IT判定用の半角大文字に統一したテキスト
    Dim str判定用 As String
    str判定用 = StrConv(str元文字列, vbUpperCase + vbNarrow)

    ' ITをひとつずつ検索
    Dim ITの位置 As Long
    Dim ひとつ前のITの位置 As Long
    Dim i As Long, 判定文字 As String
    Do
        
        ' 前回のITの次のITを検索(なければExit)
        ITの位置 = InStr(ひとつ前のITの位置 + 1, str判定用, "IT")
        If ITの位置 = 0 Then
            ReplaceIT→DX = str結果値
            Exit Function
        End If
        
        ' ITの" ","'"ではないひとつ前の文字が英字か判定
        Dim is前の文字が英字 As Boolean: is前の文字が英字 = False
        For i = 1 To ITの位置 - 1
            判定文字 = Mid(str判定用, ITの位置 - i, 1)
            If 判定文字 <> " " And 判定文字 <> "'" Then
                If 判定文字 Like "[A-Z]" Then: is前の文字が英字 = True
                Exit For
            End If
        Next
        
        ' ITの" ","'"ではないひとつ後ろの文字が英字か判定
        Dim is後ろの文字が英字 As Boolean: is後ろの文字が英字 = False
        For i = 2 To Len(str判定用) - ITの位置
            判定文字 = Mid(str判定用, ITの位置 + i, 1)
            If 判定文字 <> " " And 判定文字 <> "'" Then
                If 判定文字 Like "[A-Z]" Then is後ろの文字が英字 = True
                Exit For
            End If
        Next
        
        ' ITの両側が英字でなければDXに置換
        If (is前の文字が英字 Or is後ろの文字が英字) = False Then
            Mid(str結果値, ITの位置, 2) = "DX"
        End If
        
        ひとつ前のITの位置 = ITの位置
    Loop

End Function

解説

各見出しコメントの通りのロジックで処理を進めています。


まずは「IT」を検索し、そのITのひとつ前/ひとつ後ろの文字を判定して、
どちらも英字ではなかった場合は置換を実行しています。


置換の実行はITとDXの文字数が一致してくれているため、
Midステートメントで実行しています。


Midは右辺に書くとMid関数ではなくステートメントとして動き、
第○文字目からn文字分を置き換えることが出来ます。

今回のように「同じ文字でも置換するものとしないものがある」際には、
便利に扱えるステートメントですので覚えておきましょう。


ひとつ前/ひとつ後ろの文字をただ判定するだけなら一重ループでよいのですが、
今回は半角スペースとシングルクォートを無視する必要があるため、
前方・後方に再度ループを回す必要があります。


このあたりのロジックは変数名をしっかりつけると頭を整理しやすくなる、
というか雑な変数名にすると頭がパンクします。

本コードの命名をひとつ参考にしてみてください。


最後にひとつ、変数の使い方についてですが、
今回のこちら↓のコード、

ITの位置 = InStr(ひとつ前のITの位置 + 1, str判定用, "IT")

 
これは以下のコード↓でも全く同じ動きになります。

ITの位置 = InStr(ITの位置 + 1, str判定用, "IT")

 
この代入が行われるまではITの位置には前回のITの位置が入っていますからね。

↓こちらのコードは無駄と言えば無駄な処理をしています。

ひとつ前のITの位置 = ITの位置

 

とはいえ、たかがLong変数ひとつの消費メモリと、代入1回の処理時間は、
このFunctionを1億回呼んでも0といっていい程度です。


こういった複雑な処理では脳の負担を少しでも減らすことが重要ですので、
(↑の変数を用意した方が分かりやすいと思う方は、)
躊躇せずにこういった説明変数を使っていきましょう。




以上の内容はhttps://www.limecode.jp/entry/fungo/replace-it-with-dxより取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14