置換ツールの作成

# はじめに
詳細設計書に定義されている内容が膨大かつ単純な実装だったため、一括でコードを作成するためのツールを作成していく

# ツールの仕様
excelマクロ(vba)で作成する。
テンプレートフォーマットに対して設計書の値を埋めていくような形で作る。
例えば以下のHTMLを使用して説明する。
```.html
        <label for="name">名前：</label><br>
        <input type="text" id="name" name="name" required><br><br>

        <label for="email">メールアドレス：</label><br>
        <input type="email" id="email" name="email" required><br><br>
```
　
 名前やメールアドレスのようなフォームを大量に作成する必要があるとして、
必ず一致する部分と一致しない部分を明確にする。
```テンプレート.html
        <label for="A">B：</label><br>
        <input type="C" id="A" name="A" required><br><br>
```
A,B,Cと3つの置換値が必要だとわかる。

コードはページ最後に記載する。

以下のようにシートを用意する。
文言や色は適当でいいがセルの場所は一致させるように。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/fe85476e-7a45-e3a2-2040-3d6881d36787.png)
　
 ツール使用手順
1. A～Cの3つをループさせるので3を記入する。
2. A1以降の行数にA～Cに置換したい値を記入する。
3. I1のテンプレに1つ目のテンプレートに対応するように[セル]を当てはめる。
```html:I1セル用テンプレート
        <label for="[A2]">[A3]：</label><br>
        <input type="[A4]" id="[A2]" name="[A2]" required><br><br>
```




- 実行前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/14c85ee9-d655-aeaa-7dc9-1ab39c1c650a.png)
　
 - 実行後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/b4c249a3-1d87-4f14-77f8-41047c457c08.png)
テンプレートが2つ出力された。

 出力結果のE列をコピーすると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/37a095c5-81e4-8992-fd4d-61e69bff1d91.png)
テンプレート毎の前後に"がつくので一括置換で削除
`"`が`""`になってしまうので`""`を`"`に一括置換する。



 :::note info
補足
以下正規表現でテンプレートの前後の"は一括で削除できる。
`^"|.(?=\r\n)`

 テンプレート内で改行していると\nが含まれる。以下で\nのみを\r\nに置換できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/f3359695-7808-a71e-981a-c107ea832013.png)
:::


- 整形後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/1d587e48-b4cc-4eae-93ed-339d241ec61e.png)


# 他の機能
- D列
D1以降の行もA1以降と同じように使用できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/1561a644-0618-a4d1-8c3e-78e0113535dd.png)

- テンプレート凡例（前後削除も可能）
[A3]⇒A3セルに置換
[D4]⇒D4セルに置換
[A5f1]⇒A5セルの前1文字を省き、置換
[D6b2]⇒D6セルの後ろ2文字を省き、置換
[A10F2B1]⇒A10セルの前2文字、後ろ1文字を省き、置換

- 処理開始時
出力結果を削除する。

- 処理の終了タイミング
次のテンプレートのAとD列の両方の値が空の場合。

# ソースコード
```sql
Sub CreateTemplate()
    Dim i As Integer
    Dim outputRow As Integer
    Dim template As String
    Dim aValue As String
    Dim dValue As String
    Dim rowsPerTemplate As Integer
    Dim customAValue As String
    Dim customDValue As String
    Dim customNumber As Integer
    Dim placeholder As String
    Dim startPos As Integer
    Dim endPos As Integer
    Dim fPos As Integer
    Dim bPos As Integer
    
    ' I1セルからテンプレート文字列を取得
    template = Range("I1").Value
    
    ' A1セルからループする行数を取得
    rowsPerTemplate = Range("A1").Value
    
    ' E列のE2以降のセルを削除しておく（E1以外）
    If Not IsEmpty(Range("E2").Value) Then
        Range("E2:E" & Cells(Rows.Count, 5).End(xlUp).Row).ClearContents
    End If

    ' 出力を開始する行（E列の行番号）
    outputRow = 2
    
    ' A列とD列のデータを順番に処理するループ
    i = 2 ' 最初のデータ行（A2とD2）
    ' A列とD列両方が空でない限りループ
    Do While Not (Cells(i, 1).Value = "" And Cells(i, 4).Value = "")
        ' ループする行数分だけテンプレートを生成
        Dim currentTemplate As String
        currentTemplate = template ' テンプレート文字列をコピー
        
        ' テンプレート内の[A]や[D]の部分をA列とD列の値で置換
        For j = 0 To rowsPerTemplate - 1
            ' A列とD列の値を取得してテンプレートに挿入
            aValue = Cells(i + j, 1).Value ' A列の値
            dValue = Cells(i + j, 4).Value ' D列の値
            
            ' [A]と[D]を対応するセルの値に置換
            currentTemplate = Replace(currentTemplate, "[A" & (j + 2) & "]", aValue)
            currentTemplate = Replace(currentTemplate, "[D" & (j + 2) & "]", dValue)
            
            ' [A2bX]の場合は末尾のX文字を削除
            placeholder = "[A" & (j + 2) & "b"
            startPos = InStr(currentTemplate, placeholder)
            If startPos > 0 Then
                ' bプレースホルダーを見つけた場合、末尾の文字数を取得
                endPos = InStr(startPos, currentTemplate, "]")
                If endPos > 0 Then
                    ' b数字（X）を抽出
                    customNumber = CInt(Mid(currentTemplate, startPos + Len(placeholder), endPos - startPos - Len(placeholder)))
                    ' A列の値から末尾X文字を削除
                    customAValue = Left(aValue, Len(aValue) - customNumber)
                    ' bプレースホルダーを置換
                    currentTemplate = Replace(currentTemplate, placeholder & customNumber & "]", customAValue)
                End If
            End If
            
            ' [A2fX]の場合は先頭のX文字を削除
            placeholder = "[A" & (j + 2) & "f"
            startPos = InStr(currentTemplate, placeholder)
            If startPos > 0 Then
                ' fプレースホルダーを見つけた場合、先頭の文字数を取得
                endPos = InStr(startPos, currentTemplate, "]")
                If endPos > 0 Then
                    ' f数字（X）を抽出
                    customNumber = CInt(Mid(currentTemplate, startPos + Len(placeholder), endPos - startPos - Len(placeholder)))
                    ' A列の値から先頭X文字を削除
                    customAValue = Mid(aValue, customNumber + 1)
                    ' fプレースホルダーを置換
                    currentTemplate = Replace(currentTemplate, placeholder & customNumber & "]", customAValue)
                End If
            End If

            ' [D2bX]の場合は末尾のX文字を削除
            placeholder = "[D" & (j + 2) & "b"
            startPos = InStr(currentTemplate, placeholder)
            If startPos > 0 Then
                ' bプレースホルダーを見つけた場合、末尾の文字数を取得
                endPos = InStr(startPos, currentTemplate, "]")
                If endPos > 0 Then
                    ' b数字（X）を抽出
                    customNumber = CInt(Mid(currentTemplate, startPos + Len(placeholder), endPos - startPos - Len(placeholder)))
                    ' D列の値から末尾X文字を削除
                    customDValue = Left(dValue, Len(dValue) - customNumber)
                    ' bプレースホルダーを置換
                    currentTemplate = Replace(currentTemplate, placeholder & customNumber & "]", customDValue)
                End If
            End If

            ' [D2fX]の場合は先頭のX文字を削除
            placeholder = "[D" & (j + 2) & "f"
            startPos = InStr(currentTemplate, placeholder)
            If startPos > 0 Then
                ' fプレースホルダーを見つけた場合、先頭の文字数を取得
                endPos = InStr(startPos, currentTemplate, "]")
                If endPos > 0 Then
                    ' f数字（X）を抽出
                    customNumber = CInt(Mid(currentTemplate, startPos + Len(placeholder), endPos - startPos - Len(placeholder)))
                    ' D列の値から先頭X文字を削除
                    customDValue = Mid(dValue, customNumber + 1)
                    ' fプレースホルダーを置換
                    currentTemplate = Replace(currentTemplate, placeholder & customNumber & "]", customDValue)
                End If
            End If

            ' [A2F2B3]の場合は先頭2文字と末尾3文字を削除
            placeholder = "[A" & (j + 2) & "F"
            startPos = InStr(currentTemplate, placeholder)
            If startPos > 0 Then
                ' Fプレースホルダーを見つけた場合、先頭の文字数を取得
                endPos = InStr(startPos, currentTemplate, "B")
                If endPos > 0 Then
                    ' F数字（X）を抽出
                    fPos = CInt(Mid(currentTemplate, startPos + Len(placeholder), endPos - startPos - Len(placeholder)))
                    
                    ' Bプレースホルダーを見つけた場合、末尾の文字数を取得
                    bPos = InStr(endPos, currentTemplate, "]")
                    If bPos > 0 Then
                        ' B数字（Y）を抽出
                        customNumber = CInt(Mid(currentTemplate, endPos + 1, bPos - endPos - 1))
                        ' A列の値から先頭F文字と末尾B文字を削除
                        customAValue = Mid(aValue, fPos + 1, Len(aValue) - fPos - customNumber)
                        ' FとBプレースホルダーを置換
                        currentTemplate = Replace(currentTemplate, "[A" & (j + 2) & "F" & fPos & "B" & customNumber & "]", customAValue)
                    End If
                End If
            End If

            ' [D2F2B3]の場合は先頭2文字と末尾3文字を削除
            placeholder = "[D" & (j + 2) & "F"
            startPos = InStr(currentTemplate, placeholder)
            If startPos > 0 Then
                ' Fプレースホルダーを見つけた場合、先頭の文字数を取得
                endPos = InStr(startPos, currentTemplate, "B")
                If endPos > 0 Then
                    ' F数字（X）を抽出
                    fPos = CInt(Mid(currentTemplate, startPos + Len(placeholder), endPos - startPos - Len(placeholder)))
                    
                    ' Bプレースホルダーを見つけた場合、末尾の文字数を取得
                    bPos = InStr(endPos, currentTemplate, "]")
                    If bPos > 0 Then
                        ' B数字（Y）を抽出
                        customNumber = CInt(Mid(currentTemplate, endPos + 1, bPos - endPos - 1))
                        ' D列の値から先頭F文字と末尾B文字を削除
                        customDValue = Mid(dValue, fPos + 1, Len(dValue) - fPos - customNumber)
                        ' FとBプレースホルダーを置換
                        currentTemplate = Replace(currentTemplate, "[D" & (j + 2) & "F" & fPos & "B" & customNumber & "]", customDValue)
                    End If
                End If
            End If
        Next j
        
        ' 結果をE列に出力
        Cells(outputRow, 5).Value = currentTemplate
        
        ' E列に出力したセルの折り返しを無効にする
        Cells(outputRow, 5).WrapText = False
        
        ' 次のテンプレートを出力するために行番号を変更
        outputRow = outputRow + 1
        
        ' 次のテンプレートを作成するために行番号を進める
        i = i + rowsPerTemplate
    Loop
End Sub
```