アフィリエイト・アドセンス広告を利用しています。詳細は こちら

Excel VBA - 区切り文字で文字列が連結されたセルからグループ単位別に行分割処理メモ

Excel VBA で区切り文字で文字列が連結されたセルから、グループ単位別に行分割する VBA コードを公開します。

Excel と Excel Visual Basic Editor(VBE)の環境設定については 以前公開した記事 より、VBA コードの基本的な内容については こちらの記事 よりご確認ください。

Excel VBA - 区切り文字で文字列が連結されたセルからグループ別に行分割処理メモ



区切り文字で文字列が連結されたセルからグループ別に行分割用サンプルファイル(xlsx ファイル)

区切り文字で文字列が連結されたセルからグループ単位別に行分割用のサンプルファイル(xlsx ファイル)を公開します。

サンプルデータは Start Point さんのところで公開しているコピペで使える都道府県一覧リスト・県庁所在地一覧 を加工しています。

こちらで作成した 地方区分別行分割A.xlsx ファイル地方区分別行分割B.xlsx ファイル を用意しました。ファイル名リンクをクリックすると Google ドライブからダウンロードするようにしています。

地方区分別行分割A.xlsx ファイル は VBA コードを実行する前の状態、地方区分別行分割B.xlsx ファイル は VBA コード実行後の処理結果内容となっています。

いずれも xlsx ファイルとなっており VBA コードは含まれていません。VBA コードを実行するにはファイル拡張子が xlsm(マクロ有効ブック)となっている必要がありますが、xlsm 形式での配布は念のため避けています。

VBA コードを実行するには 地方区分別行分割A.xlsx ファイル をダウンロード後 xlsm 形式に保存、次のセクションで紹介している VBA コード を追加して実行してもらう形としています。

VBA コードの追加方法は VBE のプロジェクトエクスプローラー(Ctrl + R キー)画面にて、開いている VBAProject(ファイル名.xlsm)→「標準モジュール」を開き、右クリックから「挿入」→「標準モジュール」でクリック、追加した標準モジュールに VBA コードを貼り付けることで動作できるようにしています。

区切り文字で文字列が連結されたセルからグループ単位で行分割処理する VBA コードと詳細な内容については 次のセクション から順番に説明します。

区切り文字で文字列が連結されたセルからグループ別に行分割処理 VBA サンプルコード

以下、区切り文字で文字列が連結されたセルから、グループ別に行方向に分割処理する VBA サンプルコードです。

この VBA コードはシート「地方区分グループ化文字列連結」のセル内改行で連結された都道府県(B 列)と県庁所在地(C 列)の文字列を、地方区分(A 列)別に行単位で分割します。

例えば地方区分の東北地方には 1つのセルに 6県ありますがこれを 6行に分割します。行分割後、地方区分列の各行のセルに東北地方の記載がある状態で各都道府県・庁所在地別に行分割します。なお、北海道地方は 1つしかないので行分割はしません。

区切り文字で連結されている都道府県と県庁所在地を地方区分単位で複数行に分割後は、シート「地方区分別行分割」に反映する流れとなっています。

なお、この処理は 前回公開した記事 Excel VBA - 区切り文字を使ったグループ単位別各行セル内文字列連結処理メモ の逆処理バージョン になります。

ただ、行分割するには複雑な条件分岐が必要なため、この VBA コードでは 1次元と 2次元配列に各種関数(LBound・UBound・Split・InStr・Replace・Len・Left・Mid)を駆使することで行分割処理を実現しています。

非常に長い VBA コードになっていますが、これは各処理ごとに Select Case ステートメントを多用しているためです。各 Case 節ではいろいろなコードを用意していますが、どれを選んで実行しても処理結果は同じになるようにしています。

注意点としてこの VBA コードでは、地方区分別に 1つセルで連結されている都道府県と県庁所在地の区切り文字数が同じであることが前提としています。双方の区切り文字数が一致しない場合は、行分割する前の段階のエラーチェックで終了するようにしています。

区切り文字で文字列が連結されたセルからグループ別に行分割処理部分以外の基本的な VBA コードについては 以前公開した記事内容 を参照してください。

次のセクション から区切り文字で文字列が連結されたセルから、グループ別に行分割処理がある VBA コード部分について内容を説明します。

2023/12/7 追記

以下の VBA コードにはメモリリークを起こす可能性があります。詳細は こちら

こちら でメモリリークを対策した VBA コードを公開します。

Option Explicit

Sub SplitRowsCells1()
  ' 地方区分を基準としてグループ化したシート「地方区分グループ化文字列連結」をシート「地方区分都道府県県庁所在地リスト」に戻す処理
  ' 1行に文字列を連結した都道府県・県庁所在地の文字列を地方区分別に行分割

  ' 実行速度計測開始
  Dim starttime As Double
  starttime = Timer

' ----------

  ' カウンタ用変数(一見見分けにくい文字同士を組み合わせない形、i と j、m と n、o(オー) と 0(ゼロ))
  Dim i As Long, k As Long, m As Long, p As Long

' ----------

  ' シート格納用オブジェクト変数
  Dim ws1 As Worksheet, ws2 As Worksheet, ws3 As Worksheet

  ' オブジェクト変数にシートセット
  Set ws1 = ThisWorkbook.Worksheets("地方区分グループ化文字列連結") ' セル分割対象シートをオブジェクト変数にセット
  Set ws2 = ThisWorkbook.Worksheets("地方区分別行分割") ' セル分割後データ貼り付け先シートをオブジェクト変数にセット
'  Set ws3 = ThisWorkbook.Worksheets("temp") ' 一致したデータ出力先テスト用シート

' ----------

  ' 最終行取得用変数
  Dim maxrow1 As Long

  ' シート最終行取得して変数に格納
  maxrow1 = ws1.Cells(Rows.Count, "A").End(xlUp).Row

  ' 最終列取得用変数
  Dim maxcol1 As Long

  ' シートの最終列取得して変数に格納
  maxcol1 = ws1.Cells(1, Columns.Count).End(xlToLeft).Column

' ----------

  ' シートの指定したセル範囲を配列として格納する動的配列
  Dim data1() As Variant

  ' シートの指定した範囲内セルを配列として動的配列に格納
  data1 = ws1.Range(ws1.Cells(2, 1), ws1.Cells(maxrow1, maxcol1)).Value

  ' Range オブジェクトを受け取り、2次元配列で返す自作関数 GetArrFromRange
'  data1 = GetArrFromRange.GetArrFromRange(ws1.Range(ws1.Cells(2, 1), ws1.Cells(maxrow1, maxcol1)))

' ----------

  ' 都道府県列と県庁所在地列、両列の区切り文字数チェック処理(区切り文字数が一致しない場合処理終了)

  ' 区切り文字数カウント用配列宣言
  Dim sumdelimiter() As Variant ' 区切り文字数合計用配列
  Dim cntdelimiter() As Variant ' 1セルに含まれる区切り文字数格納用配列

  ' 区切り文字数合計を格納する都道府県・県庁所在地列の動的配列を作成
  ReDim sumdelimiter(1) ' sumdelimiter(0) - 都道府県列区切り文字数合計、sumdelimiter(1) - 県庁所在地列区切り文字数合計
  For i = LBound(sumdelimiter) To UBound(sumdelimiter)
    sumdelimiter(i) = 0 ' 初期値 0 設定
  Next i

  ' 1セルに含まれる区切り文字数を格納する都道府県・県庁所在地列の動的配列を作成
  ReDim cntdelimiter(1) ' sumdelimiter(0) - 1セルに含まれる都道府県列区切り文字数格納、sumdelimiter(1) - 1セルに含まれる県庁所在地列区切り文字数格納
  For i = LBound(cntdelimiter) To UBound(cntdelimiter)
    cntdelimiter(i) = 0 ' 初期値 0 設定
  Next i

  ' Array 関数を使って配列の各要素に初期値 0 設定(動的配列(ReDim)や For 文を使わない場合)
'  sumdelimiter = Array(0, 0)
'  cntdelimiter = Array(0, 0)

  ' Select Case ステートメント用変数宣言
  Dim val1 As Long
  val1 = 1 ' Select Case ステートメント Case 1 ~ Case 4 まで処理を用意、1 ~ 4 のいずれかの値を指定

  ' 変数 val1 の値に応じて Case 1 ~ Case 4 のいずれかの処理を実行
  Select Case val1

  Case 1 ' Len 関数と Len 関数+ Replace 関数を使って文字数の差分から区切り文字数を計算・合計

    For i = LBound(data1, 1) To UBound(data1, 1) ' 1次元最大要素までループ処理
      For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
        ' 配列 data1 の i 行 k 列目の文字数を Len 関数でカウント(区切り文字(vbLf)削除前文字数)
        ' Replace 関数で配列 data1 の i 行 k 列目の区切り文字(vbLf)を "" で削除して Len 関数でカウント(区切り文字(vbLf)削除後文字数)
        ' 区切り文字(vbLf)削除前文字数から区切り文字(vbLf)削除後文字数を差し引き区切り文字数をカウントして、配列 cntdelimiter(k - 2) に代入
        cntdelimiter(k - 2) = Len(data1(i, k)) - Len(Replace(data1(i, k), vbLf, ""))
        ' 配列 sumdelimiter(k - 2) で区切り文字数 cntdelimiter(k - 2) を合計
        sumdelimiter(k - 2) = sumdelimiter(k - 2) + cntdelimiter(k - 2)
      Next k

      ' cntdelimiter(0)(都道府県列)と cntdelimiter(1)(県庁所在地列)の値(区切り文字数)が一致しない場合 Sub プロシージャー終了
      If cntdelimiter(0) <> cntdelimiter(1) Then
        MsgBox "地方区分「" & data1(i, 1) & "」の区切り文字数が一致しないため処理を終了します" & vbCrLf & _
        "都道府県列区切り文字数「" & cntdelimiter(0) & "」、県庁所在地列区切り文字数「" & cntdelimiter(1) & "」"
        Exit Sub
      End If

    Next i

  Case 2 ' Case 1 の 2行の区切り文字数計算式と合計式を 1行にまとめ

    For i = LBound(data1, 1) To UBound(data1, 1) ' 1次元最大要素までループ処理
      For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
        ' cntdelimiter(k - 2) = Len(data1(i, k)) - Len(Replace(data1(i, k), vbLf, ""))
        ' sumdelimiter(k - 2) = sumdelimiter(k - 2) + cntdelimiter(k - 2)
        ' 2行の計算式を 1行にまとめ
        sumdelimiter(k - 2) = sumdelimiter(k - 2) + (Len(data1(i, k)) - Len(Replace(data1(i, k), vbLf, "")))
      Next k
    Next i

  Case 3 ' Split 関数で区切り文字で配列に格納された文字列を分割、Ubound 関数で要素番号の最大値を返して区切り文字数を計算・合計

    For i = LBound(data1, 1) To UBound(data1, 1) ' 1次元最大要素までループ処理
      For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
        If UBound(Split(data1(i, k), vbLf)) = -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty で Ubound・Split 関数で -1 を返す場合
          cntdelimiter(k - 2) = 0 ' 区切り文字がないため区切り文字数格納用配列 cntdelimiter(k - 2) に 0 を代入
        ElseIf UBound(Split(data1(i, k), vbLf)) <> -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty ではない場合
          cntdelimiter(k - 2) = UBound(Split(data1(i, k), vbLf)) ' Ubound・Split 関数結果を配列 cntdelimiter(k - 2)に代入
        End If
        sumdelimiter(k - 2) = sumdelimiter(k - 2) + cntdelimiter(k - 2) ' 区切り文字数格納用配列 cntdelimiter(k - 2) を区切り文字数合計用配列 sumdelimiter(k - 2)に加算して格納
      Next k

      ' cntdelimiter(0)(都道府県列)と cntdelimiter(1)(県庁所在地列)の値(区切り文字数)が一致しない場合 Sub プロシージャー終了
      If cntdelimiter(0) <> cntdelimiter(1) Then
        MsgBox "地方区分「" & data1(i, 1) & "」の区切り文字数が一致しないため処理を終了します" & vbCrLf & _
        "都道府県列区切り文字数「" & cntdelimiter(0) & "」、県庁所在地列区切り文字数「" & cntdelimiter(1) & "」"
        Exit Sub
      End If

    Next i

  Case 4 ' Case 3 とほぼ同じ処理内容で区切り文字数格納用配列 cntdelimiter(k - 2) を使わずに、Ubound・Split 関数の結果と合計用配列 sumdelimiter(k - 2) を使って計算・合計

    For i = LBound(data1, 1) To UBound(data1, 1) ' 1次元最大要素までループ処理
      For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
        If UBound(Split(data1(i, k), vbLf)) = -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty で Ubound・Split 関数で -1 を返す場合
          sumdelimiter(k - 2) = sumdelimiter(k - 2) ' 区切り文字がないため合計用配列 sumdelimiter(k - 2) に sumdelimiter(k - 2) を代入(変更なし)
        ElseIf UBound(Split(data1(i, k), vbLf)) <> -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty ではない場合
          sumdelimiter(k - 2) = sumdelimiter(k - 2) + UBound(Split(data1(i, k), vbLf)) ' 区切り文字数合計用配列 sumdelimiter(k - 2) と Ubound・Split 関数の結果を使って計算・合計
        End If
      Next k
    Next i

  Case Else ' エラー処理(Sub プロシージャー終了)
  
    MsgBox "変数 val1 に指定された値(1~4)以外の " & val1 & " が代入されているため処理を終了します"
    Exit Sub

  End Select

  ' 区切り文字数合計用配列 sumdelimiter(0)(都道府県列)と sumdelimiter(1)(県庁所在地列)の値をイミディエイトウィンドウに表示(デバッグ用)
  Debug.Print sumdelimiter(0) & "," & sumdelimiter(1)

  ' sumdelimiter(0)(都道府県列)と sumdelimiter(1)(県庁所在地列)の値(区切り文字数)が一致しない場合 Sub プロシージャー終了
  If sumdelimiter(0) <> sumdelimiter(1) Then
    MsgBox "区切り文字数合計が一致しないため処理を終了します" & vbCrLf & _
    "都道府県列区切り文字数合計「" & sumdelimiter(0) & "」、県庁所在地列区切り文字数合計「" & sumdelimiter(1) & "」"
    Exit Sub
  End If

' ----------

  ' 都道府県・県庁所在地列カウント処理(区切り文字数チェック処理をクリアできれば都道府県・県庁所在地ともに必ず 47 になる)
  ' ここの処理結果で配列 sumstring()に格納した値(47)を使って、次に区切り文字から分割した地方区分別の都道府県・県庁所在地を格納する配列を作成

  ' 都道府県・県庁所在地列カウント用配列宣言
  Dim sumstring() As Variant ' 都道府県・県庁所在地数合計用配列
  Dim cntstring() As Variant ' 1セルに含まれる都道府県・県庁所在地数格納用配列

  ' 地名数合計を格納する都道府県・県庁所在地列の動的配列を作成
  ReDim sumstring(1) ' sumstring(0) - 都道府県数合計、sumstring(1) - 県庁所在地数合計
  For i = LBound(sumstring) To UBound(sumstring)
    sumstring(i) = 0 ' 初期値 0 設定
  Next i

  ' 1セルに含まれる地名数を格納する都道府県・県庁所在地列の動的配列を作成
  ReDim cntstring(1) ' cntstring(0) - 1セルに含まれる都道府県数格納、cntstring(1) - 1セルに含まれる県庁所在地数格納
  For i = LBound(cntstring) To UBound(cntstring)
    cntstring(i) = 0 ' 初期値 0 設定
  Next i

  ' Array 関数を使って配列の各要素に初期値 0 設定(動的配列(ReDim)や For 文を使わない)
'  sumstring = Array(0, 0)
'  cntstring = Array(0, 0)

  ' Select Case ステートメント用変数宣言
  Dim val2 As Long
  val2 = 1 ' Select Case ステートメント Case 1 と Case 2 の処理を用意、1~2 のいずれかの値を指定

  ' 変数 val2 の値に応じて Case 1 か Case 2 のいずれかの処理を実行
  Select Case val2

  Case 1 ' Split 関数で区切り文字で配列に格納された文字列を分割、Ubound 関数で要素番号の最大値に +1 して都道府県・県庁所在地数を計算・合計

    For i = LBound(data1, 1) To UBound(data1, 1) ' 1次元最大要素までループ処理
      For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
        If UBound(Split(data1(i, k), vbLf)) = -1 Then ' Ubound・Split 関数結果で区切り文字がない場合 -1 を返す時の処理
          cntstring(k - 2) = 1 ' 都道府県・県庁所在地数格納用配列 cntstring(k - 2) に 1 を代入(全国都道府県・県庁所在地数帳尻合わせのため)
        ElseIf UBound(Split(data1(i, k), vbLf)) <> -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty ではない場合
          cntstring(k - 2) = UBound(Split(data1(i, k), vbLf)) + 1 ' Ubound・Split 関数結果を配列 cntstring(k - 2)に代入
        End If
        sumstring(k - 2) = sumstring(k - 2) + cntstring(k - 2) ' 都道府県・県庁所在地数格納用配列 cntstring(k - 2) を都道府県・県庁所在地数合計用配列 sumstring(k - 2)に加算して格納
      Next k
    Next i

  Case 2 ' Case 1 の処理内容で都道府県・県庁所在地数格納用配列 cntstring(k - 2) を使わずに、Ubound・Split 関数の結果と合計用配列 sumstring(k - 2) を使って計算・合計

    For i = LBound(data1, 1) To UBound(data1, 1) ' 1次元最大要素までループ処理
      For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
        If UBound(Split(data1(i, k), vbLf)) = -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty で Ubound・Split 関数で -1 を返す場合
          sumstring(k - 2) = sumstring(k - 2) + 1 ' 都道府県・県庁所在地数合計用配列 sumstring(k - 2) に 1 を足して sumstring(k - 2) に代入(全国都道府県・県庁所在地数帳尻合わせのため)
        ElseIf UBound(Split(data1(i, k), vbLf)) <> -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty ではない場合
          sumstring(k - 2) = sumstring(k - 2) + UBound(Split(data1(i, k), vbLf)) + 1 ' 都道府県・県庁所在地数合計用配列 sumstring(k - 2) と Ubound・Split 関数の結果を使って計算・合計
        End If
      Next k
    Next i

  Case Else ' エラー処理(Sub プロシージャー終了)
  
    MsgBox "変数 val2 に指定された値(1~2)以外の " & val2 & " が代入されているため処理を終了します"
    Exit Sub

  End Select

  ' 都道府県・県庁所在地数合計用配列 sumstring(0)(都道府県列)と sumstring(1)(県庁所在地列)の値をイミディエイトウィンドウに表示(デバッグ用)
  Debug.Print sumstring(0) & "," & sumstring(1)

' ----------

  ' シートの指定したセル範囲を配列として格納する動的配列
  Dim data2() As Variant

  ' シートの指定した範囲内セルを配列として動的配列に格納
  ' 終点セルの行は都道府県・県庁所在地数合計用配列 sumstring(0) または sumstring(1) に + 1 で調整(どちらも値は 47)
  data2 = ws1.Range(ws1.Cells(2, LBound(data1, 1)), ws1.Cells(sumstring(0) + 1, UBound(data1, 2))).Value
'  data2 = ws1.Range(ws1.Cells(2, LBound(data1, 1)), ws1.Cells(sumstring(1) + 1, UBound(data1, 2))).Value

  ' Range オブジェクトを受け取り、2次元配列で返す自作関数 GetArrFromRange
'  data2 = GetArrFromRange.GetArrFromRange(ws1.Range(ws1.Cells(2, LBound(data1, 1)), ws1.Cells(sumstring(0) + 1, UBound(data1, 1))))
'  data2 = GetArrFromRange.GetArrFromRange(ws1.Range(ws1.Cells(2, LBound(data1, 2)), ws1.Cells(sumstring(1) + 1, UBound(data1, 2))))

  ' 地方区分・都道府県・県庁所在地格納用 2次元配列の最大要素まで Empty で初期化(繰り返し(やり直し)処理に対応)
  For i = LBound(data2, 1) To UBound(data2, 1) ' 1次元最大要素までループ処理
    For k = LBound(data2, 2) To UBound(data2, 2) ' 2次元最大要素までループ処理
      data2(i, k) = Empty ' 配列に Empty を代入して初期化
    Next k
'    data2(i, 1) = Empty ' for 文を使わない場合の書き方
'    data2(i, 2) = Empty ' for 文を使わない場合の書き方
'    data2(i, 3) = Empty ' for 文を使わない場合の書き方
  Next i

  ' Redim ステートメントを使った 2次元配列の最大要素までの初期化
'  ReDim data2(1 To UBound(data2, 1), 1 To UBound(data2, 2))

' ----------

  ' 都道府県・県庁所在地列の区切り文字間にある各地名を順番に分割して抽出、地方区分別に配列の各行列に代入(区切り文字で連結された文字列を地方区分別に分割)

  Dim arrstring As String ' 区切り文字位置特定用文字列型変数宣言
  Dim num() As Variant ' 区切り文字位置の値格納用動的配列宣言、Select Case ステートメント Case 2 と Case 3 で使用

  ' Select Case ステートメント用変数宣言
  Dim val3 As Long
  val3 = 1 ' Select Case ステートメント Case 1 ~ Case 4 の処理を用意、1 ~ 4 のいずれかの値を指定

  ' 変数 val3 の値に応じて Case 1 ~ Case 4 のいずれかの処理を実行
  Select Case val3

  Case 1 ' 変数 num1 ~ num4 に区切り文字位置の値を代入して InStr・Left(または Mid)関数を使って区切り文字位置を特定、区切り文字間にある文字列を配列に代入

    Dim num1 As Long, num2 As Long, num3 As Long, num4 As Long ' 区切り文字位置の値格納用変数宣言

    ' 区切り文字位置の値格納用変数を 0 で初期化
    num1 = 0 ' 都道府県列の各セル区切り文字がある最初の文字位置格納用変数(複数の区切り文字がある場合、num1 の文字位置から次の区切り文字がある文字位置(変数 num3)を格納して更新)
    num2 = 0 ' 県庁所在地列の各セル区切り文字がある最初の文字位置格納用変数(複数の区切り文字がある場合、num2 の文字位置から次の区切り文字がある文字位置(変数 num4)を格納して更新)
    num3 = 0 ' 都道府県列の区切り文字位置を格納した変数 num1 を基準にして、次の区切り文字がある位置格納用変数
    num4 = 0 ' 県庁所在地列の区切り文字位置を格納した変数 num3 を基準にして、次の区切り文字がある位置格納用変数

    ' カウンタ用変数 p を使って配列 data2 の p 行に(区切り文字間にある)都道府県・県庁所在地文字列を代入
    p = 1 ' 初期値として 1(行目)を設定、各 If 文の条件式で処理後、最後に p = p + 1 でインクリメントして次の行に指定

    For i = LBound(data1, 1) To UBound(data1, 1) ' 1次元最大要素までループ処理
      ' 配列 data1 の i 行 2列目または 3列目のデータを文字列型変数 arrstring に代入
      ' この後の If・For 文で文字列型変数 arrstring に対して LBound・UBound・Split 関数を使い、区切り文字数を計算・カウント、区切り文字数に応じた処理を実行
      ' 区切り文字数取得が目的のため data1(i, 2) または data1(i, 3) のどちらかだけでよい
      arrstring = data1(i, 2)
'      arrstring = data1(i, 3)

      ' 文字列型変数 arrstring に区切り文字がない場合は Ubound・Split 関数で 0 を返す、または Empty なら Ubound・Split 関数で -1 を返す場合の処理
      If UBound(Split(arrstring, vbLf)) = 0 Or UBound(Split(arrstring, vbLf)) = -1 Then
        For k = LBound(data1, 2) To UBound(data1, 2) ' 2次元最大要素までループ処理
          data2(p, k) = data1(i, k) ' 配列 data1 の i 行 k 列目のデータを、配列 data2 の p 行 k 列目に代入(区切り文字間の文字抽出処理不要)
        Next k
'        data2(p, 1) = data1(i, 1) ' for 文を使わない場合の書き方
'        data2(p, 2) = data1(i, 2) ' for 文を使わない場合の書き方
'        data2(p, 3) = data1(i, 3) ' for 文を使わない場合の書き方

        p = p + 1 ' 配列 data2 の p 行をインクリメント(+1)して次の行に指定
      End If

      ' 文字列型変数 arrstring に区切り文字がある場合の処理
      If UBound(Split(arrstring, vbLf)) > 0 Then
        ' Split 関数を使って区切り文字(vbLf)で文字列型変数 arrstring に格納された文字列を分割、Lbound・Ubound 関数で要素番号の最小値(必ず 0)と最大値を返してそれぞれ +1 を計算
        ' 区切り文字間の文字列を抽出するため、For 文で最小値(必ず 1)と最大値をカウンタ用変数 m に代入してループ処理
        For m = LBound(Split(arrstring, vbLf)) + 1 To UBound(Split(arrstring, vbLf)) + 1
          ' For 文のカウンタ用変数 m が初期値の場合(Split 関数を使って区切り文字(vbLf)で文字列型変数 arrstring に格納された文字列を分割後、Lbound 関数で要素番号の最小値(必ず 0)+1 の場合)
          ' 区切り文字がある場合、この処理は必ず最初に通る
          If m = LBound(Split(arrstring, vbLf)) + 1 Then
            num1 = InStr(m, data1(i, 2), vbLf) ' 配列 data1 の i 行 2列目(都道府県列)データを、Instr 関数で m(= 1)文字目から区切り文字(vbLf)がある最初の位置の値を変数 num1 に格納
            num2 = InStr(m, data1(i, 3), vbLf) ' 配列 data1 の i 行 3列目(県庁所在地列)データを、Instr 関数で m(= 1)文字目から区切り文字(vbLf)がある最初の位置の値を変数 num2 に格納

            data2(p, 1) = data1(i, 1) ' 配列 data1 の i 行 1列目(地方区分)のデータを、配列 data2 の p 行 1列目に格納
            data2(p, 2) = Left(data1(i, 2), num1 - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Left 関数で、最初の区切り文字位置のひとつ前(num1 - 1)までの文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Left(data1(i, 3), num2 - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Left 関数で、最初の区切り文字位置のひとつ前(num2 - 1)までの文字列を取得、配列 data2 の p 行 3列目に格納
'            data2(p, 2) = Mid(data1(i, 2), m, num1 - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、変数 m 文字目から最初の区切り文字位置のひとつ前(num1 - 1)までの文字列を取得、配列 data2 の p 行 2列目に格納
'            data2(p, 3) = Mid(data1(i, 3), m, num2 - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、変数 m 文字目から最初の区切り文字位置のひとつ前(num2 - 1)までの文字列を取得、配列 data2 の p 行 3列目に格納

            p = p + 1 ' 配列 data2 の p 行をインクリメント(+1)して次の行に指定
          End If

          ' for 文のカウンタ用変数 m が初期値以外かつ最終値以外の場合(Split 関数を使って区切り文字(vbLf)で文字列型変数 arrstring に格納された文字列を分割後、Lbound 関数で要素番号の最小値(必ず 0)+1 以外かつ最大値 +1 以外の場合)
          ' 例としてカウンタ用変数 m が 1 ~ 4 場合 2 と 3 が条件に合致、変数 m が 1 ~ 3 の場合 2 が条件合致、変数 m が 1 ~ 2 の場合はどちらも初期値(要素番号最小値 +1)と最終値(要素番号最大値 +1)のため条件に合致しない
          If m <> LBound(Split(arrstring, vbLf)) + 1 And m <> UBound(Split(arrstring, vbLf)) + 1 Then
            num3 = InStr(num1 + 1, data1(i, 2), vbLf) ' 配列 data1 の i 行 2列目(都道府県列)データを Instr 関数で、変数 num1 に格納されている区切り文字位置の値の次の位置(num1 + 1)から次の区切り文字(vbLf)がある位置の値を変数 num3 に格納
            num4 = InStr(num2 + 1, data1(i, 3), vbLf) ' 配列 data1 の i 行 2列目(県庁所在地)データを Instr 関数で、変数 num1 に格納されている区切り文字位置の値の次の位置(num2 + 1)から次の区切り文字(vbLf)がある位置の値を変数 num4 に格納

            data2(p, 1) = data1(i, 1) ' 配列 data1 の i 行 1列目(地方区分)のデータを、配列 data2 の p 行 1列目に格納
            data2(p, 2) = Mid(data1(i, 2), num1 + 1, num3 - num1 - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、変数 num1 に格納されている区切り文字位置の次の位置(num1 + 1)から次の区切り文字位置のひとつ前までの文字数(num3 - num1 - 1)を指定して文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Mid(data1(i, 3), num2 + 1, num4 - num2 - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、変数 num2 に格納されている区切り文字位置の次の位置(num2 + 1)から次の区切り文字位置のひとつ前までの文字数(num4 - num2 - 1)を指定して文字列を取得、配列 data2 の p 行 3列目に格納

            num1 = num3 ' 配列 data1 の i 行 2列目(都道府県)の区切り文字開始位置の値(num1)を、次の区切り文字位置の値(num3)に更新(複数の区切り文字がある場合の繰り返し処理対応)
            num2 = num4 ' 配列 data1 の i 行 3列目(県庁所在地)の区切り文字開始位置の値(num2)を、次の区切り文字位置の値(num4)に更新(複数の区切り文字がある場合の繰り返し処理対応)

            p = p + 1 ' 配列 data2 の p 行をインクリメント(+1)して次の行に指定
          End If

          ' For 文のカウンタ用変数 m が最終値の場合(Split 関数を使って区切り文字(vbLf)で文字列型変数 arrstring に格納された文字列を分割後、Lbound 関数で要素番号の最大値 +1 の場合)
          ' 例としてカウンタ用変数 m が 1 ~ 3 場合 3 が条件に合致、変数 m が 1 ~ 2 の場合 2 が条件合致
          ' 区切り文字がある場合、この処理は必ず最後に通る
          If m = UBound(Split(arrstring, vbLf)) + 1 Then
            data2(p, 1) = data1(i, 1) ' 配列 data1 の i 行 1列目(地方区分)のデータを、配列 data2 の p 行 1列目に格納
            data2(p, 2) = Mid(data1(i, 2), num1 + 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、変数 num1 に格納されている最後の区切り文字位置の次の位置(num1 + 1)からデータ終端まで文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Mid(data1(i, 3), num2 + 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、変数 num2 に格納されている最後の区切り文字位置の次の位置(num2 + 1)からデータ終端まで文字列を取得、配列 data2 の p 行 3列目に格納

            p = p + 1 ' 配列 data2 の p 行をインクリメント(+1)して次の行に指定
          End If
        Next m

        ' カウンタ用変数 i をインクリメントして配列 data1(i, 1)の次の地方区分行に進む前に、区切り文字位置の値格納用変数すべてを 0 で初期化
        num1 = 0
        num2 = 0
        num3 = 0
        num4 = 0

      End If

    Next i

  Case 2 ' Case 1 と同じ処理内容、変更点は区切り文字位置の値格納用変数 num1 ~ num4 を使わず、代わりに区切り文字位置の値格納用動的配列 num() を使用

    ' 区切り文字位置の値格納用動的配列 num() を定義して初期値設定
    ReDim num(3) ' 区切り文字位置の値格納用変数 num1 ~ num4 の個数分(全部で 4つ)要素数を定義
    For i = LBound(num) To UBound(num) ' 動的配列の最大要素までループ処理
      num(i) = 0 ' 動的配列 num の i 番目に 0 を設定
    Next i
'    num = Array(0, 0, 0, 0) ' 動的配列と for 文を使わない場合の書き方

    p = 1

    For i = LBound(data1, 1) To UBound(data1, 1)
      arrstring = data1(i, 2)

      If UBound(Split(arrstring, vbLf)) = 0 Or UBound(Split(arrstring, vbLf)) = -1 Then
        For k = LBound(data1, 2) To UBound(data1, 2)
          data2(p, k) = data1(i, k)
        Next k
'        data2(p, 1) = data1(i, 1)
'        data2(p, 2) = data1(i, 2)
'        data2(p, 3) = data1(i, 3)

        p = p + 1
      End If

      If UBound(Split(arrstring, vbLf)) > 0 Then
        For m = LBound(Split(arrstring, vbLf)) + 1 To UBound(Split(arrstring, vbLf)) + 1
          If m = LBound(Split(arrstring, vbLf)) + 1 Then
            num(0) = InStr(m, data1(i, 2), vbLf) ' 配列 data1 の i 行 2列目(都道府県列)データを、Instr 関数で m(= 1)文字目から区切り文字(vbLf)がある最初の位置の値を動的配列 num(0) に格納
            num(1) = InStr(m, data1(i, 3), vbLf) ' 配列 data1 の i 行 3列目(県庁所在地列)データを、Instr 関数で m(= 1)文字目から区切り文字(vbLf)がある最初の位置の値を動的配列 num(1) に格納

            data2(p, 1) = data1(i, 1)
            data2(p, 2) = Left(data1(i, 2), num(0) - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Left 関数で、最初の区切り文字位置のひとつ前(num(0) - 1)までの文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Left(data1(i, 3), num(1) - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Left 関数で、最初の区切り文字位置のひとつ前(num(1) - 1)までの文字列を取得、配列 data2 の p 行 3列目に格納

'            data2(p, 2) = Mid(data1(i, 2), m, num(0) - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、変数 m 文字目から最初の区切り文字位置のひとつ前(num(0) - 1)までの文字列を取得、配列 data2 の p 行 2列目に格納
'            data2(p, 3) = Mid(data1(i, 3), m, num(1) - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、変数 m 文字目から最初の区切り文字位置のひとつ前(num(1) - 1)までの文字列を取得、配列 data2 の p 行 3列目に格納

            p = p + 1
          End If

          If m <> LBound(Split(arrstring, vbLf)) + 1 And m <> UBound(Split(arrstring, vbLf)) + 1 Then
            num(2) = InStr(num(0) + 1, data1(i, 2), vbLf) ' 配列 data1 の i 行 2列目(都道府県列)データを Instr 関数で、動的配列 num(0) に格納されている区切り文字位置の次の位置(num(0) + 1)から次の区切り文字(vbLf)がある位置の値を動的配列 num(2) に格納
            num(3) = InStr(num(1) + 1, data1(i, 3), vbLf) ' 配列 data1 の i 行 2列目(県庁所在地)データを Instr 関数で、動的配列 num(1) に格納されている区切り文字位置の次の位置(num(1) + 1)から次の区切り文字(vbLf)がある位置の値を動的配列 num(3) に格納
            
            data2(p, 1) = data1(i, 1)
            data2(p, 2) = Mid(data1(i, 2), num(0) + 1, num(2) - num(0) - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、動的配列 num(0) に格納されている区切り文字位置の次の位置(num(0) + 1)から次の区切り文字位置のひとつ前までの文字数(num(2) - num(0) - 1)を指定して文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Mid(data1(i, 3), num(1) + 1, num(3) - num(1) - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、動的配列 num(1) に格納されている区切り文字位置の次の位置(num(1) + 1)から次の区切り文字位置のひとつ前までの文字数(num(3) - num(1) - 1)を指定して文字列を取得、配列 data2 の p 行 3列目に格納

            num(0) = num(2) ' 配列 data1 の i 行 2列目(都道府県)の区切り文字開始位置の値(num(0))を、次の区切り文字位置の値(num(2))に更新(複数の区切り文字がある場合の繰り返し処理対応)
            num(1) = num(3) ' 配列 data1 の i 行 3列目(県庁所在地)の区切り文字開始位置の値(num(1))を、次の区切り文字位置の値(num(3))に更新(複数の区切り文字がある場合の繰り返し処理対応)

            p = p + 1
          End If

          If m = UBound(Split(arrstring, vbLf)) + 1 Then
            data2(p, 1) = data1(i, 1)
            data2(p, 2) = Mid(data1(i, 2), num(0) + 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、動的配列 num(0) に格納されている最後の区切り文字位置の次の位置(num(0) + 1)からデータ終端まで文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Mid(data1(i, 3), num(1) + 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、動的配列 num(1) に格納されている最後の区切り文字位置の次の位置(num(1) + 1)からデータ終端まで文字列を取得、配列 data2 の p 行 3列目に格納

            p = p + 1
          End If
        Next m

        ' カウンタ用変数 i をインクリメントして配列 data1(i, 1)の次の地方区分行に進む前に、区切り文字位置の値格納用動的配列すべての要素を for 文を使って 0 で初期化
        For k = LBound(num) To UBound(num) ' 動的配列の最大要素までループ処理
          num(k) = 0 ' 動的配列 num の i 番目に 0 を設定
        Next k
'        num(0) = 0 ' for 文を使わない場合の書き方
'        num(1) = 0 ' for 文を使わない場合の書き方
'        num(2) = 0 ' for 文を使わない場合の書き方
'        num(3) = 0 ' for 文を使わない場合の書き方

      End If

    Next i

  Case 3 ' Case 2 と同じ処理内容、変更点は各配列の行・列・要素番号への直接値の指定からカウンタ用変数 k と For 文を使ってループ処理に変更

    ReDim num(3)
    For i = LBound(num) To UBound(num)
      num(i) = 0
    Next i
'    num = Array(0, 0, 0, 0)

    p = 1

    For i = LBound(data1, 1) To UBound(data1, 1)
      arrstring = data1(i, 2)

      If UBound(Split(arrstring, vbLf)) = 0 Or UBound(Split(arrstring, vbLf)) = -1 Then
        For k = LBound(data1, 2) To UBound(data1, 2)
          data2(p, k) = data1(i, k)
        Next k
'        data2(p, 1) = data1(i, 1)
'        data2(p, 2) = data1(i, 2)
'        data2(p, 3) = data1(i, 3)

        p = p + 1
      End If

      If UBound(Split(arrstring, vbLf)) > 0 Then
        For m = LBound(Split(arrstring, vbLf)) + 1 To UBound(Split(arrstring, vbLf)) + 1
          If m = LBound(Split(arrstring, vbLf)) + 1 Then
            data2(p, 1) = data1(i, 1)

            For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
              num(k - 2) = InStr(m, data1(i, k), vbLf) ' 配列 data1 の i 行 k 列目(都道府県列・県庁所在地)データを、Instr 関数で m(= 1)文字目から区切り文字(vbLf)がある最初の位置の値を動的配列 num(k - 2) に格納
              data2(p, k) = Left(data1(i, k), num(k - 2) - 1) ' 配列 data1 の i 行 k 列目(都道府県・県庁所在地)のデータを Left 関数で、最初の区切り文字位置のひとつ前(num(k - 2) - 1)までの文字列を取得、配列 data2 の p 行 k 列目に格納
'              data2(p, k) = Mid(data1(i, k), m, num(k - 2) - 1) ' 配列 data1 の i 行 k 列目(都道府県・県庁所在地)のデータを Mid 関数で、変数 m 文字目から最初の区切り文字位置のひとつ前(num(k - 2) - 1)までの文字列を取得、配列 data2 の p 行 k 列目に格納
            Next k
'            num(0) = InStr(m, data1(i, 2), vbLf)
'            num(1) = InStr(m, data1(i, 3), vbLf)

'            data2(p, 2) = Left(data1(i, 2), num(0) - 1)
'            data2(p, 3) = Left(data1(i, 3), num(1) - 1)
'            data2(p, 2) = Mid(data1(i, 2), m, num(0) - 1)
'            data2(p, 3) = Mid(data1(i, 3), m, num(1) - 1)

            p = p + 1
          End If

          If m <> LBound(Split(arrstring, vbLf)) + 1 And m <> UBound(Split(arrstring, vbLf)) + 1 Then
            data2(p, 1) = data1(i, 1)

            For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
              num(k) = InStr(num(k - 2) + 1, data1(i, k), vbLf) ' 配列 data1 の i 行 k 列目(都道府県列・県庁所在地)データを Instr 関数で、動的配列 num(k - 2) に格納されている区切り文字位置の次の位置(num(k - 2) + 1)から次の区切り文字(vbLf)がある位置の値を動的配列 num(k) に格納
              data2(p, k) = Mid(data1(i, k), num(k - 2) + 1, num(k) - num(k - 2) - 1) ' 配列 data1 の i 行 k 列目(都道府県・県庁所在地)のデータを Mid 関数で、動的配列 num(k - 2) に格納されている区切り文字位置の次の位置(num(k - 2) + 1)から次の区切り文字位置のひとつ前までの文字数(num(k) - num(k - 2) - 1)を指定して文字列を取得、配列 data2 の p 行 k 列目に格納
              num(k - 2) = num(k) ' 配列 data1 の i 行 k 列目(都道府県・県庁所在地)の区切り文字開始位置の値(num(k))を、次の区切り文字位置の値(num(k - 2))に更新(複数の区切り文字がある場合の繰り返し処理対応)
            Next k
'            num(2) = InStr(num(0) + 1, data1(i, 2), vbLf)
'            num(3) = InStr(num(1) + 1, data1(i, 3), vbLf)

'            data2(p, 2) = Mid(data1(i, 2), num(0) + 1, num(2) - num(0) - 1)
'            data2(p, 3) = Mid(data1(i, 3), num(1) + 1, num(3) - num(1) - 1)

'            num(0) = num(2)
'            num(1) = num(3)

            p = p + 1
          End If

          If m = UBound(Split(arrstring, vbLf)) + 1 Then
            data2(p, 1) = data1(i, 1)

            For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
              data2(p, k) = Mid(data1(i, k), num(k - 2) + 1) ' 配列 data1 の i 行 k 列目(都道府県・県庁所在地)のデータを Mid 関数で、動的配列 num(k - 2) に格納されている最後の区切り文字位置の次の位置(num(k - 2) + 1)からデータ終端まで文字列を取得、配列 data2 の p 行 k 列目に格納
            Next k
'            data2(p, 2) = Mid(data1(i, 2), num(0) + 1)
'            data2(p, 3) = Mid(data1(i, 3), num(1) + 1)

            p = p + 1
          End If
        Next m

        For k = LBound(num) To UBound(num)
          num(k) = 0
        Next k
'        num(0) = 0
'        num(1) = 0
'        num(2) = 0
'        num(3) = 0

      End If

    Next i

  Case 4 ' Split 関数で配列に格納した各要素を、インクリメントしたカウンタ変数 s を使って 2次元配列 data2 の行番号を指定して各要素を格納

    Dim tmp As Variant ' Split 関数で返した配列の格納用変数
    Dim s As Long ' 2次元配列 data2 の行番号変数 p 用インクリメント変数

    p = 1
    s = 0 ' 0 で初期化

    For i = LBound(data1, 1) To UBound(data1, 1)
      arrstring = data1(i, 2)

      If UBound(Split(arrstring, vbLf)) = 0 Or UBound(Split(arrstring, vbLf)) = -1 Then
        For k = LBound(data1, 2) To UBound(data1, 2)
          data2(p, k) = data1(i, k)
        Next k
'        data2(p, 1) = data1(i, 1)
'        data2(p, 2) = data1(i, 2)
'        data2(p, 3) = data1(i, 3)

        p = p + 1
      End If

      If UBound(Split(arrstring, vbLf)) > 0 Then

        For k = LBound(data1, 2) + 1 To UBound(data1, 2)
          ' Split 関数の第 1引数に区切り文字列がある 2次元配列を、第 2引数に区切り文字(vbLf)を指定
          ' 1次元配列として返した区切られた各文字列をバリアント型変数 tmp に格納
          tmp = Split(data1(i, k), vbLf)

          ' 分割した都道府県・県庁所在地別の地方区分名を 2次元配列 data2 に格納
          If k = 2 Then ' For 文内で都道府県・県庁所在地別に行分割処理を行う際に地方区分名の代入は 1度だけでいいため、カウンタ変数 k の初期値 2(都道府県列)の時だけ地方区分名を代入処理
            For m = LBound(tmp) To UBound(tmp) ' 1次元配列 tmp の最大要素までループ処理
              data2(p + s, 1) = data1(i, 1) ' 2次元配列 data1 の地方区分名を 2次元配列 data2 に代入、2次元配列 data2 の行番号 p をインクリメントした変数 s を使って行番号指定(ループ開始処理時の変数 s の初期値は 0、ループ処理を抜けたら 0 で初期化)
              s = s + 1 ' 変数 s をインクリメントして次の行番号 p に加算
            Next m

            s = 0 ' 変数 s を 0 で初期化

          End If

          ' 分割した都道府県・県庁所在地名を 2次元配列 data2 に格納
          For m = LBound(tmp) To UBound(tmp) ' 1次元配列 tmp の最大要素までループ処理
            data2(p + s, k) = tmp(m) ' 1次元配列 tmp の都道府県名・県庁所在地名を 2次元配列 data2 に代入、2次元配列 data2 の行番号 p をインクリメントした変数 s を使って行番号指定(ループ開始処理時の変数 s の初期値は 0、ループ処理を抜けたら 0 で初期化)
            s = s + 1 ' 変数 s をインクリメントして次の行番号 p に加算
          Next m

          s = 0 ' 変数 s を 0 で初期化

        Next k

        p = p + UBound(tmp) + 1 ' 配列 data2 の行番号 p に、1次元配列 tmp の最大要素(UBound 関数使用)と 1 を足して次の配列 data2 への代入先行番号を更新(1次元配列 tmp の開始要素番号が 0 からのため + 1 で調整)

      End If

    Next i

  Case Else ' エラー処理(Sub プロシージャー終了)

    MsgBox "変数 val3 に指定された値(1~3)以外の " & val3 & " が代入されているため処理を終了します"
    Exit Sub

  End Select

' ----------

  ' 二次元配列 data2 の内容を、貼り付け先シートの Range で指定したセルから Resize で範囲を変更してセルに代入
  ws2.Range("A2").Resize(UBound(data2, 1), UBound(data2, 2)).Value = data2
  ws2.Activate

  ' テスト用シートに出力する場合は以下のテスト用シートを格納したオブジェクト変数に変更
'  ws3.Range("A2").Resize(UBound(data2, 1), UBound(data2, 2)).Value = data2
'  ws3.Activate

' ----------

  ' 実行速度計測結果表示
  Debug.Print Format(Timer - starttime, "0.00秒")
  
End Sub

VBA 以外の方法として Power Query を使うことで行方向に分割することもできます。

Select Case 都道府県列と県庁所在地列、両列の区切り文字数チェック処理(区切り文字数が一致しない場合処理終了)

  ' 都道府県列と県庁所在地列、両列の区切り文字数チェック処理(区切り文字数が一致しない場合処理終了)

  ' 区切り文字数カウント用配列宣言
  Dim sumdelimiter() As Variant ' 区切り文字数合計用配列
  Dim cntdelimiter() As Variant ' 1セルに含まれる区切り文字数格納用配列

  ' 区切り文字数合計を格納する都道府県・県庁所在地列の動的配列を作成
  ReDim sumdelimiter(1) ' sumdelimiter(0) - 都道府県列区切り文字数合計、sumdelimiter(1) - 県庁所在地列区切り文字数合計
  For i = LBound(sumdelimiter) To UBound(sumdelimiter)
    sumdelimiter(i) = 0 ' 初期値 0 設定
  Next i

  ' 1セルに含まれる区切り文字数を格納する都道府県・県庁所在地列の動的配列を作成
  ReDim cntdelimiter(1) ' sumdelimiter(0) - 1セルに含まれる都道府県列区切り文字数格納、sumdelimiter(1) - 1セルに含まれる県庁所在地列区切り文字数格納
  For i = LBound(cntdelimiter) To UBound(cntdelimiter)
    cntdelimiter(i) = 0 ' 初期値 0 設定
  Next i

  ' Array 関数を使って配列の各要素に初期値 0 設定(動的配列(ReDim)や For 文を使わない場合)
'  sumdelimiter = Array(0, 0)
'  cntdelimiter = Array(0, 0)

  ' Select Case ステートメント用変数宣言
  Dim val1 As Long
  val1 = 1 ' Select Case ステートメント Case 1 ~ Case 4 まで処理を用意、1 ~ 4 のいずれかの値を指定

  ' 変数 val1 の値に応じて Case 1 ~ Case 4 のいずれかの処理を実行
  Select Case val1

行分割処理をする前に都道府県列と県庁所在地列、両列が一対一で対応しているかどうかチェックします。

都道府県列と県庁所在地列が一対一で対応しているかどうかは、両列の区切り文字数が一致しているかどうかで判定します。区切り文字数が一致しない場合は処理を終了します。

56~57行目に区切り文字数を格納する動的配列を宣言します。この動的配列は 1次元配列として扱います。56行目の sumdelimiter には区切り文字数の合計を、57行目の cntdelimiter には 1セルに含まれる区切り文字数を格納します。

60~63行目では 56行目の動的配列から都道府県・県庁所在地列の区切り文字数合計を格納する 1次元配列を作成、66~69行目では 57行目の動的配列から都道府県・県庁所在地列の 1セルに含まれる区切り文字数を格納する 1次元配列を作成します。

60行目の ReDim ステートメントで sumdelimiter(0) に都道府県列区切り文字数合計を、sumdelimiter(1) に県庁所在地列区切り文字数合計を格納します。66行目も同様に ReDim ステートメントで cntdelimiter(0) に 1セルに含まれる都道府県列区切り文字数合計を、cntdelimiter(1) に 1セルに含まれる県庁所在地列区切り文字数合計を格納します。あとは For 文で一応初期化をしています。

ReDim ステートメントと For 文を使わない別の方法として、72~73行目のように Array 関数を使って配列の要素数作成と初期値を設定する書き方があります。

76行目に Select Case ステートメント用の変数の宣言と、77行目に処理させたい Case 節の値を格納します。ここでは Case 1 ~ Case 4 まで処理を用意しているので、1 ~ 4 のいずれかの値を指定します。Case 1 ~ Case 4 に分けているのはコード内容(書き方および処理内容)が違うだけで、どれを実行しても処理結果は同じです。

なお、ここでは 1 ~ 4 以外の値を指定すると Case Else に飛び、メッセージを表示(149行目)させて Exit Sub(150行目)で Sub プロシージャーを終了させます。

80行目の Select Case に 76行目に宣言した変数をセットして、各 Case 節(Case 1Case 2Case 3Case 4)に飛び、区切り文字数のチェック処理を行い、最後に 都道府県・県庁所在地別合計区切り文字数チェック処理 する流れとなっています。

ただし Case 1Case 3 では各セル単位で区切り文字数のチェックが可能なので、この時点で一致しなかった場合は 都道府県・県庁所在地別合計区切り文字数チェック処理 まで飛ばずに処理を終了します。

Case 1 - Len 関数と Len 関数 + Replace 関数を使って文字数の差分から区切り文字数を計算・合計と区切り文字数チェック処理

  Case 1 ' Len 関数と Len 関数+ Replace 関数を使って文字数の差分から区切り文字数を計算・合計

    For i = LBound(data1, 1) To UBound(data1, 1) ' 1次元最大要素までループ処理
      For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
        ' 配列 data1 の i 行 k 列目の文字数を Len 関数でカウント(区切り文字(vbLf)削除前文字数)
        ' Replace 関数で配列 data1 の i 行 k 列目の区切り文字(vbLf)を "" で削除して Len 関数でカウント(区切り文字(vbLf)削除後文字数)
        ' 区切り文字(vbLf)削除前文字数から区切り文字(vbLf)削除後文字数を差し引き区切り文字数をカウントして、配列 cntdelimiter(k - 2) に代入
        cntdelimiter(k - 2) = Len(data1(i, k)) - Len(Replace(data1(i, k), vbLf, ""))
        ' 配列 sumdelimiter(k - 2) で区切り文字数 cntdelimiter(k - 2) を合計
        sumdelimiter(k - 2) = sumdelimiter(k - 2) + cntdelimiter(k - 2)
      Next k

      ' cntdelimiter(0)(都道府県列)と cntdelimiter(1)(県庁所在地列)の値(区切り文字数)が一致しない場合 Sub プロシージャー終了
      If cntdelimiter(0) <> cntdelimiter(1) Then
        MsgBox "地方区分「" & data1(i, 1) & "」の区切り文字数が一致しないため処理を終了します" & vbCrLf & _
        "都道府県列区切り文字数「" & cntdelimiter(0) & "」、県庁所在地列区切り文字数「" & cntdelimiter(1) & "」"
        Exit Sub
      End If

    Next i

Len 関数と Len 関数 + Replace 関数を使って、文字数の差分から区切り文字数を計算・合計を行う、区切り文字数チェック処理です。

84~85行目の For 文で 2次元配列 data1 に格納された区切り文字があるセルをループ処理します。

1セルに含まれる区切り文字数の計算方法ですが、Len 関数で 1セルに含まれる全文字数から Len 関数 + Replace 関数で区切り文字を除いた文字数を差し引くことで求められます。これを 89行目で処理しています。

Len(data1(i, k)) の Len 関数で 1セルに含まれる全文字数を計算、これには区切り文字であるセル内改行(vbLf)も 1文字としてカウントされます。

Len(Replace(data1(i, k), vbLf, "")) では区切り文字であるセル内改行(vbLf)を Replace 関数の "" で削除して、区切り文字削除後の文字数を Len 関数でカウントしています。

Len(data1(i, k)) - Len(Replace(data1(i, k), vbLf, "")) で全文字数から区切り文字削除後の文字数を差し引くことで、区切り文字数(vbLf)を計算できます。これを 1次元配列 cntdelimiter の要素番号を指定して代入することで、都道府県列と県庁所在地列の区切り文字数を格納しています。

91行目では 1次元配列 cntdelimiter に格納された値を別の 1次元配列 sumdelimiter の同じ要素番号を指定して値を合算、再び 1次元配列 sumdelimiter に代入することでループ処理内で 2次元配列 data1 に含まれる区切り文字数の合計を計算できます。

95行目で各セルの区切り文字数を格納した 1次元配列 cntdelimiter を使うことで、ループ処理内で逐次現在の地方区分の都道府県列と県庁所在地列の区切り文字数が一致しているかどうか判定することできます。

If 文で cntdelimiter(0) <> cntdelimiter(1) で区切り文字が一致しなかった場合、96~97行目で一致しなかった地方区分と都道府県列区切り文字数・県庁所在地列区切り文字数をメッセージで表示させて、98行目の Exit Sub で Sub プロシージャーを終了させています。

なお、Select Case ステートメントを抜けた後に 158行目で 都道府県・県庁所在地別合計区切り文字数チェック処理 でも同様なチェックをしてますが、こちらは 1次元配列 sumdelimiter を使った 2次元配列 data1 の 都道府県と県庁所在地の 合計区切り文字数 が一致するかどうかを判定しています。

Case 2 - Case 1 の 2行の区切り文字数計算式と合計式を 1行にまとめ

  Case 2 ' Case 1 の 2行の区切り文字数計算式と合計式を 1行にまとめ

    For i = LBound(data1, 1) To UBound(data1, 1) ' 1次元最大要素までループ処理
      For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
        ' cntdelimiter(k - 2) = Len(data1(i, k)) - Len(Replace(data1(i, k), vbLf, ""))
        ' sumdelimiter(k - 2) = sumdelimiter(k - 2) + cntdelimiter(k - 2)
        ' 2行の計算式を 1行にまとめ
        sumdelimiter(k - 2) = sumdelimiter(k - 2) + (Len(data1(i, k)) - Len(Replace(data1(i, k), vbLf, "")))
      Next k
    Next i

Case 2 では、Case 1 の 2行の区切り文字数計算式(89行目)と合計式(91行目)を、110行目で 1行にまとめたコードです。

1セルに含まれる区切り文字数を格納する 1次元配列 cntdelimiter を使用していないため、Case 1 にあったループ処理内で逐次、現在の地方区分の都道府県列と県庁所在地列の区切り文字数の一致判定処理はできません。

Select Case ステートメントを抜けた後の 158行目 都道府県・県庁所在地別合計区切り文字数チェック処理 で判定するようにしています。

Case 3 - Split 関数で区切り文字で配列に格納された文字列を分割、Ubound 関数で要素番号の最大値を返して区切り文字数を計算・合計と区切り文字数チェック処理

  Case 3 ' Split 関数で区切り文字で配列に格納された文字列を分割、Ubound 関数で要素番号の最大値を返して区切り文字数を計算・合計

    For i = LBound(data1, 1) To UBound(data1, 1) ' 1次元最大要素までループ処理
      For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
        If UBound(Split(data1(i, k), vbLf)) = -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty で Ubound・Split 関数で -1 を返す場合
          cntdelimiter(k - 2) = 0 ' 区切り文字がないため区切り文字数格納用配列 cntdelimiter(k - 2) に 0 を代入
        ElseIf UBound(Split(data1(i, k), vbLf)) <> -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty ではない場合
          cntdelimiter(k - 2) = UBound(Split(data1(i, k), vbLf)) ' Ubound・Split 関数結果を配列 cntdelimiter(k - 2)に代入
        End If
        sumdelimiter(k - 2) = sumdelimiter(k - 2) + cntdelimiter(k - 2) ' 区切り文字数格納用配列 cntdelimiter(k - 2) を区切り文字数合計用配列 sumdelimiter(k - 2)に加算して格納
      Next k

      ' cntdelimiter(0)(都道府県列)と cntdelimiter(1)(県庁所在地列)の値(区切り文字数)が一致しない場合 Sub プロシージャー終了
      If cntdelimiter(0) <> cntdelimiter(1) Then
        MsgBox "地方区分「" & data1(i, 1) & "」の区切り文字数が一致しないため処理を終了します" & vbCrLf & _
        "都道府県列区切り文字数「" & cntdelimiter(0) & "」、県庁所在地列区切り文字数「" & cntdelimiter(1) & "」"
        Exit Sub
      End If

    Next i

Case 1 は Len 関数と Replace 関数を使った 1セルに含まれる区切り文字数を計算する方法でしたが、Case 3 では If 文と UBound 関数と Split 関数を組み合わせて区切り文字数を計算する方法です。

118行目の If 文と 120行目の ElseIf 文にある UBound(Split(data1(i, k), vbLf)) は、2次元配列 data1 の各要素に格納された文字列を Split 関数で区切り文字(vbLf)を指定、区切られた各文字列を配列として返して、UBound 関数で要素数の最大値を求めています。

118行目の条件式で -1 かどうか判定しているのは、対象データ(ここでは 2次元配列の各要素)が空(Empty)だった場合 -1 を返すことになるので、まずその対策として判定しています。この場合、区切り文字数がないことになるので 119行目で 0 を代入しています。(今回用意したデータは空(Empty)はないので本来であれば不要ですが、エラー対策として一応用意しています)

120行目では 118行目と同じ関数を使って不等号 <> で -1 以外であれば、121行目で UBound(Split(data1(i, k), vbLf)) の返り値(区切り文字数)を代入しています。なお、区切り文字がない(北海道地方のように 1項目しかない)場合は 1次元配列の最大要素は 0 になるので、0 を代入します。(1次元配列の要素数は 1 になるが、UBound 関数での最大要素は 0 となるため)

残りのコード部分は Case 1 と同じです。

Case 4 - Case 3 とほぼ同じ処理内容で区切り文字数格納用配列を使わずに、Ubound・Split 関数の結果と区切り文字数合計用配列を使って計算・合計

  Case 4 ' Case 3 とほぼ同じ処理内容で区切り文字数格納用配列 cntdelimiter(k - 2) を使わずに、Ubound・Split 関数の結果と合計用配列 sumdelimiter(k - 2) を使って計算・合計

    For i = LBound(data1, 1) To UBound(data1, 1) ' 1次元最大要素までループ処理
      For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
        If UBound(Split(data1(i, k), vbLf)) = -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty で Ubound・Split 関数で -1 を返す場合
          sumdelimiter(k - 2) = sumdelimiter(k - 2) ' 区切り文字がないため合計用配列 sumdelimiter(k - 2) に sumdelimiter(k - 2) を代入(変更なし)
        ElseIf UBound(Split(data1(i, k), vbLf)) <> -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty ではない場合
          sumdelimiter(k - 2) = sumdelimiter(k - 2) + UBound(Split(data1(i, k), vbLf)) ' 区切り文字数合計用配列 sumdelimiter(k - 2) と Ubound・Split 関数の結果を使って計算・合計
        End If
      Next k
    Next i

Case 3 とほぼ同じ処理内容で区切り文字数格納用配列 cntdelimiter を使わずに、Ubound・Split 関数の結果と区切り文字数合計用配列 sumdelimiter を使って計算・合計します。

140行目は sumdelimiter(k - 2) = sumdelimiter(k - 2) と、同じ値を代入しているため値の変更はありません。わざわざ入れる必要はありませんが、これまでの If 文を使った条件分岐後の値の処理として明示的に入れておきます。

なお、142行目の sumdelimiter(k - 2) = sumdelimiter(k - 2) + UBound(Split(data1(i, k), vbLf)) は、Case 2 の 110行目にあるコード sumdelimiter(k - 2) = sumdelimiter(k - 2) + (Len(data1(i, k)) - Len(Replace(data1(i, k), vbLf, ""))) と同じ処理結果を得られます。

Case 2 と同様にループ処理内で逐次、現在の地方区分の都道府県列と県庁所在地列の区切り文字数の一致判定処理はできないため、Select Case ステートメントを抜けた後の 158行目 都道府県・県庁所在地別合計区切り文字数チェック処理 で判定しています。

Case Else(エラー処理)と都道府県・県庁所在地別合計区切り文字数チェック処理

  Case Else ' エラー処理(Sub プロシージャー終了)
  
    MsgBox "変数 val1 に指定された値(1~4)以外の " & val1 & " が代入されているため処理を終了します"
    Exit Sub

  End Select

  ' 区切り文字数合計用配列 sumdelimiter(0)(都道府県列)と sumdelimiter(1)(県庁所在地列)の値をイミディエイトウィンドウに表示(デバッグ用)
  Debug.Print sumdelimiter(0) & "," & sumdelimiter(1)

  ' sumdelimiter(0)(都道府県列)と sumdelimiter(1)(県庁所在地列)の値(区切り文字数)が一致しない場合 Sub プロシージャー終了
  If sumdelimiter(0) <> sumdelimiter(1) Then
    MsgBox "区切り文字数合計が一致しないため処理を終了します" & vbCrLf & _
    "都道府県列区切り文字数合計「" & sumdelimiter(0) & "」、県庁所在地列区切り文字数合計「" & sumdelimiter(1) & "」"
    Exit Sub
  End If

Case Else(エラー処理)といずれかの Case 節(Case 1Case 2Case 3Case 4)を抜けた後の都道府県・県庁所在地別合計区切り文字数チェック処理です。

Select Case ステートメント用変数 に各 Case 節以外の値を代入した場合、147行目の Case Else(エラー処理)に飛び 149行目でメッセージを表示させて 150行目の Exit Sub で Sub プロシージャーを終了するようにしています。

155行目の Debug.Print ではデバッグウィンドウに都道府県・県庁所在地別合計区切り文字数を表示しています。

158行目で各 Case 節で計算した合計区切り文字数を格納した 1次元配列 sumdelimiter を、If 文で sumdelimiter(0) <> sumdelimiter(1) で区切り文字が一致しなかった場合、159~160行目で一致しなかった地方区分と合計都道府県列区切り文字数・合計県庁所在地列区切り文字数をメッセージで表示させて、161行目の Exit Sub で Sub プロシージャーを終了させています。

この 158行目の内容は Case 1Case 3 にある、ループ処理内で逐次現在の地方区分の都道府県列と県庁所在地列の区切り文字数が一致しなかった場合の判定と終了処理と同じコードです。1次元配列に cntdelimiter を使っている点だけが異なります。

ちなみに Case 2Case 4 には区切り文字数一致判定コードがないため、このセクションで判定処理をしています。

以上の都道府県列と県庁所在地列双方の区切り文字数チェック処理がクリアできたら、次のセクション では都道府県数と県庁所在地数のカウント処理を行います。

Select Case 都道府県・県庁所在地列カウント処理

  ' 都道府県・県庁所在地列カウント処理(区切り文字数チェック処理をクリアできれば都道府県・県庁所在地ともに必ず 47 になる)
  ' ここの処理結果で配列 sumstring()に格納した値(47)を使って、次に区切り文字から分割した地方区分別の都道府県・県庁所在地を格納する配列を作成

  ' 都道府県・県庁所在地列カウント用配列宣言
  Dim sumstring() As Variant ' 都道府県・県庁所在地数合計用配列
  Dim cntstring() As Variant ' 1セルに含まれる都道府県・県庁所在地数格納用配列

  ' 地名数合計を格納する都道府県・県庁所在地列の動的配列を作成
  ReDim sumstring(1) ' sumstring(0) - 都道府県数合計、sumstring(1) - 県庁所在地数合計
  For i = LBound(sumstring) To UBound(sumstring)
    sumstring(i) = 0 ' 初期値 0 設定
  Next i

  ' 1セルに含まれる地名数を格納する都道府県・県庁所在地列の動的配列を作成
  ReDim cntstring(1) ' cntstring(0) - 1セルに含まれる都道府県数格納、cntstring(1) - 1セルに含まれる県庁所在地数格納
  For i = LBound(cntstring) To UBound(cntstring)
    cntstring(i) = 0 ' 初期値 0 設定
  Next i

  ' Array 関数を使って配列の各要素に初期値 0 設定(動的配列(ReDim)や For 文を使わない)
'  sumstring = Array(0, 0)
'  cntstring = Array(0, 0)

  ' Select Case ステートメント用変数宣言
  Dim val2 As Long
  val2 = 1 ' Select Case ステートメント Case 1 と Case 2 の処理を用意、1~2 のいずれかの値を指定

  ' 変数 val2 の値に応じて Case 1 か Case 2 のいずれかの処理を実行
  Select Case val2

都道府県列と県庁所在地列、両列の区切り文字数チェック処理 後、行分割時に都道府県と県庁所在地を格納するのに必要な 2次元配列の要素数を求めます。なお、この時点ではまだ 2次元配列は作成しません。

基本的な処理の流れおよびコード内容は 都道府県列と県庁所在地列の区切り文字数チェック処理 と同じです。以下大きく相違点があるところを説明します。

170~171行目で都道府県・県庁所在地数を格納する動的配列を宣言しています。前に宣言した配列 を流用することも可能ですが、ここでは別の変数を宣言して念のため区別させています。

190行目に Select Case ステートメント用の変数の宣言と、191行目に処理させたい Case 節の値を格納します。ここも変数については 前に宣言した変数 の流用が可能ですが、区別のため新しく変数を宣言しています。

ここでは Case 1Case 2 の処理を用意しているので、1 ~ 2 のいずれかの値を指定します。ここも各 Case 節に分けているのはコード内容(書き方および処理内容)が違うだけで、どれを実行しても処理結果は同じです。

1 ~ 2 以外の値を指定すると Case Else に飛び、メッセージを表示(223行目)させて Exit Sub(224行目)で Sub プロシージャーを終了させるところもそのままです。

Case 1 - Split 関数で区切り文字で配列に格納された文字列を分割、Ubound 関数で要素番号の最大値に +1 して都道府県・県庁所在地数を計算・合計

  Case 1 ' Split 関数で区切り文字で配列に格納された文字列を分割、Ubound 関数で要素番号の最大値に +1 して都道府県・県庁所在地数を計算・合計

    For i = LBound(data1, 1) To UBound(data1, 1) ' 1次元最大要素までループ処理
      For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
        If UBound(Split(data1(i, k), vbLf)) = -1 Then ' Ubound・Split 関数結果で区切り文字がない場合 -1 を返す時の処理
          cntstring(k - 2) = 1 ' 都道府県・県庁所在地数格納用配列 cntstring(k - 2) に 1 を代入(全国都道府県・県庁所在地数帳尻合わせのため)
        ElseIf UBound(Split(data1(i, k), vbLf)) <> -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty ではない場合
          cntstring(k - 2) = UBound(Split(data1(i, k), vbLf)) + 1 ' Ubound・Split 関数結果を配列 cntstring(k - 2)に代入
        End If
        sumstring(k - 2) = sumstring(k - 2) + cntstring(k - 2) ' 都道府県・県庁所在地数格納用配列 cntstring(k - 2) を都道府県・県庁所在地数合計用配列 sumstring(k - 2)に加算して格納
      Next k
    Next i

If 文と Lbound・Ubound 関数と Split 関数を使った都道府県・県庁所在地数の計算・合計方法です。コード内容は Case 3 の区切り文字数計算・合計処理 とほぼ同じです。以下変更点です。

考え方として区切り文字数に + 1 を加算することで都道府県・県庁所在地数を求めることができます。

201行目では右辺の 0 → 1 に変更、203行目では右辺に + 1 を加算することで都道府県・県庁所在地数を求めています。

Case 2 - Case 1 の処理内容で都道府県・県庁所在地数格納用配列を使わずに、Ubound・Split 関数の結果と合計用配列を使って計算・合計

  Case 2 ' Case 1 の処理内容で都道府県・県庁所在地数格納用配列 cntstring(k - 2) を使わずに、Ubound・Split 関数の結果と合計用配列 sumstring(k - 2) を使って計算・合計

    For i = LBound(data1, 1) To UBound(data1, 1) ' 1次元最大要素までループ処理
      For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
        If UBound(Split(data1(i, k), vbLf)) = -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty で Ubound・Split 関数で -1 を返す場合
          sumstring(k - 2) = sumstring(k - 2) + 1 ' 都道府県・県庁所在地数合計用配列 sumstring(k - 2) に 1 を足して sumstring(k - 2) に代入(全国都道府県・県庁所在地数帳尻合わせのため)
        ElseIf UBound(Split(data1(i, k), vbLf)) <> -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty ではない場合
          sumstring(k - 2) = sumstring(k - 2) + UBound(Split(data1(i, k), vbLf)) + 1 ' 都道府県・県庁所在地数合計用配列 sumstring(k - 2) と Ubound・Split 関数の結果を使って計算・合計
        End If
      Next k
    Next i

If 文と Lbound・Ubound 関数と Split 関数を使った都道府県・県庁所在地数の合計を求める方法です。コード内容は Case 4 の区切り文字数合計処理 とほぼ同じです。以下変更点です。

考え方として 前出の Case 1 と同様に、区切り文字数に + 1 を加算することで都道府県・県庁所在地数を求めることができます。

214行目および 216行目の右辺に + 1 を加算することで都道府県・県庁所在地数の合計を求めています。

Case Else(エラー処理)と都道府県数と県庁所在地数の合計表示(デバッグ用)

  Case Else ' エラー処理(Sub プロシージャー終了)
  
    MsgBox "変数 val2 に指定された値(1~2)以外の " & val2 & " が代入されているため処理を終了します"
    Exit Sub

  End Select

  ' 都道府県・県庁所在地数合計用配列 sumstring(0)(都道府県列)と sumstring(1)(県庁所在地列)の値をイミディエイトウィンドウに表示(デバッグ用)
  Debug.Print sumstring(0) & "," & sumstring(1)

Case Else(エラー処理)といずれかの Case 節(Case 1Case 2)を抜けた後の都道府県・県庁所在地数合計を表示します。

Select Case ステートメント用変数 に各 Case 節以外の値を代入した場合、223行目の Case Else(エラー処理)に飛び 149行目でメッセージを表示させて 224行目の Exit Sub で Sub プロシージャーを終了するようにしています。

229行目の Debug.Print でデバッグウィンドウに都道府県・県庁所在地数合計を表示しています。

次のセクション ではこの結果をもとに、都道府県・県庁所在地を格納する 2次元配列を作成して地方区分単位別に行分割処理をします。

都道府県・県庁所在地列の区切り文字間にある各地名を順番に分割して抽出、地方区分別に配列の各行列に代入

  ' シートの指定したセル範囲を配列として格納する動的配列
  Dim data2() As Variant

  ' シートの指定した範囲内セルを配列として動的配列に格納
  ' 終点セルの行は都道府県・県庁所在地数合計用配列 sumstring(0) または sumstring(1) に + 1 で調整(どちらも値は 47)
  data2 = ws1.Range(ws1.Cells(2, LBound(data1, 1)), ws1.Cells(sumstring(0) + 1, UBound(data1, 1))).Value
'  data2 = ws1.Range(ws1.Cells(2, LBound(data1, 2)), ws1.Cells(sumstring(1) + 1, UBound(data1, 2))).Value

  ' Range オブジェクトを受け取り、2次元配列で返す自作関数 GetArrFromRange
'  data2 = GetArrFromRange.GetArrFromRange(ws1.Range(ws1.Cells(2, LBound(data1, 1)), ws1.Cells(sumstring(0) + 1, UBound(data1, 1))))
'  data2 = GetArrFromRange.GetArrFromRange(ws1.Range(ws1.Cells(2, LBound(data1, 2)), ws1.Cells(sumstring(1) + 1, UBound(data1, 2))))

  ' 地方区分・都道府県・県庁所在地格納用 2次元配列の最大要素まで Empty で初期化(繰り返し(やり直し)処理に対応)
  For i = LBound(data2, 1) To UBound(data2, 1) ' 1次元最大要素までループ処理
    For k = LBound(data2, 2) To UBound(data2, 2) ' 2次元最大要素までループ処理
      data2(i, k) = Empty ' 配列に Empty を代入して初期化
    Next k
'    data2(i, 1) = Empty ' for 文を使わない場合の書き方
'    data2(i, 2) = Empty ' for 文を使わない場合の書き方
'    data2(i, 3) = Empty ' for 文を使わない場合の書き方
  Next i

  ' Redim ステートメントを使った 2次元配列の最大要素までの初期化
'  ReDim data2(1 To UBound(data2, 1), 1 To UBound(data2, 2))

' ----------

  ' 都道府県・県庁所在地列の区切り文字間にある各地名を順番に分割して抽出、地方区分別に配列の各行列に代入(区切り文字で連結された文字列を地方区分別に分割)

  Dim arrstring As String ' 区切り文字位置特定用文字列型変数宣言
  Dim num() As Variant ' 区切り文字位置の値格納用動的配列宣言、Select Case ステートメント Case 2 と Case 3 で使用

  ' Select Case ステートメント用変数宣言
  Dim val3 As Long
  val3 = 3 ' Select Case ステートメント Case 1 ~ Case 4 の処理を用意、1 ~ 4 のいずれかの値を指定

  ' 変数 val3 の値に応じて Case 1 ~ Case 4 のいずれかの処理を実行
  Select Case val3

都道府県・県庁所在地列カウント処理 後、行分割時に必要な都道府県と県庁所在地を格納するのに必要な 2次元配列を作成します。

238行目で Range プロパティの範囲指定を使ってセルを範囲を取得して 2次元配列を作成します。

Cells プロパティの終点セルには行番号に 都道府県・県庁所在地列カウント処理 で計算した、都道府県数を格納した 1次元配列 sumstring(0) + 1 を指定しています。+ 1 を入れているのは 1次元配列は要素番号 0 から格納されているので、要素数をカウントするのに + 1 で調整しているためです。

ちなみに 239行目は Cells プロパティの終点セルの行番号に、県庁所在地数を格納した 1次元配列 sumstring(1) + 1 を指定しています。1次元配列 sumstring(0) と sumstring(1) はどちらも同じ値が格納されているので、238行目・239行目どちらを実行しても同じ結果になります。

262行目および263行目は各 Case 節で使用する変数の宣言します。262行目の String 型変数はすべての Case 節で使用、263行目の動的配列は Case 2Case 3 で使用します。

266行目に Select Case ステートメント用の変数の宣言と、267行目に処理させたい Case 節の値を格納します。ここも変数については 前に宣言した変数 の流用が可能ですが、区別のため新しく宣言しています。

ここでは各 Case 節(Case 1Case 2Case 3Case 4)の処理を用意しているので、1 ~ 4 のいずれかの値を指定します。ここも各 Case 節に分けているのはコード内容(書き方および処理方法)が違うだけで、どれを実行しても処理結果は同じです。

1 ~ 4 以外の値を指定すると 585行目の Case Else に飛び、メッセージを表示(587行目)させて Exit Sub(588行目)で Sub プロシージャーを終了させるところもこれまでと同じです。

Case 1 - 変数に区切り文字位置の値を代入して InStr・Left(または Mid)関数を使って区切り文字位置を特定、区切り文字間にある文字列を配列に代入

  Case 1 ' 変数 num1 ~ num4 に区切り文字位置の値を代入して InStr・Left(または Mid)関数を使って区切り文字位置を特定、区切り文字間にある文字列を配列に代入

    Dim num1 As Long, num2 As Long, num3 As Long, num4 As Long ' 区切り文字位置の値格納用変数宣言

    ' 区切り文字位置の値格納用変数を 0 で初期化
    num1 = 0 ' 都道府県列の各セル区切り文字がある最初の文字位置格納用変数(複数の区切り文字がある場合、num1 の文字位置から次の区切り文字がある文字位置(変数 num3)を格納して更新)
    num2 = 0 ' 県庁所在地列の各セル区切り文字がある最初の文字位置格納用変数(複数の区切り文字がある場合、num2 の文字位置から次の区切り文字がある文字位置(変数 num4)を格納して更新)
    num3 = 0 ' 都道府県列の区切り文字位置を格納した変数 num1 を基準にして、次の区切り文字がある位置格納用変数
    num4 = 0 ' 県庁所在地列の区切り文字位置を格納した変数 num3 を基準にして、次の区切り文字がある位置格納用変数

    ' カウンタ用変数 p を使って配列 data2 の p 行に(区切り文字間にある)都道府県・県庁所在地文字列を代入
    p = 1 ' 初期値として 1(行目)を設定、各 If 文の条件式で処理後、最後に p = p + 1 でインクリメントして次の行に指定

    For i = LBound(data1, 1) To UBound(data1, 1) ' 1次元最大要素までループ処理
      ' 配列 data1 の i 行 2列目または 3列目のデータを文字列型変数 arrstring に代入
      ' この後の If・For 文で文字列型変数 arrstring に対して LBound・UBound・Split 関数を使い、区切り文字数を計算・カウント、区切り文字数に応じた処理を実行
      ' 区切り文字数取得が目的のため data1(i, 2) または data1(i, 3) のどちらかだけでよい
      arrstring = data1(i, 2)
'      arrstring = data1(i, 3)

      ' 文字列型変数 arrstring に区切り文字がない場合は Ubound・Split 関数で 0 を返す、または Empty なら Ubound・Split 関数で -1 を返す場合の処理
      If UBound(Split(arrstring, vbLf)) = 0 Or UBound(Split(arrstring, vbLf)) = -1 Then
        For k = LBound(data1, 2) To UBound(data1, 2) ' 2次元最大要素までループ処理
          data2(p, k) = data1(i, k) ' 配列 data1 の i 行 k 列目のデータを、配列 data2 の p 行 k 列目に代入(区切り文字間の文字抽出処理不要)
        Next k
'        data2(p, 1) = data1(i, 1) ' for 文を使わない場合の書き方
'        data2(p, 2) = data1(i, 2) ' for 文を使わない場合の書き方
'        data2(p, 3) = data1(i, 3) ' for 文を使わない場合の書き方

        p = p + 1 ' 配列 data2 の p 行をインクリメント(+1)して次の行に指定
      End If

      ' 文字列型変数 arrstring に区切り文字がある場合の処理
      If UBound(Split(arrstring, vbLf)) > 0 Then
        ' Split 関数を使って区切り文字(vbLf)で文字列型変数 arrstring に格納された文字列を分割、Lbound・Ubound 関数で要素番号の最小値(必ず 0)と最大値を返してそれぞれ +1 を計算
        ' 区切り文字間の文字列を抽出するため、For 文で最小値(必ず 1)と最大値をカウンタ用変数 m に代入してループ処理
        For m = LBound(Split(arrstring, vbLf)) + 1 To UBound(Split(arrstring, vbLf)) + 1
          ' For 文のカウンタ用変数 m が初期値の場合(Split 関数を使って区切り文字(vbLf)で文字列型変数 arrstring に格納された文字列を分割後、Lbound 関数で要素番号の最小値(必ず 0)+1 の場合)
          ' 区切り文字がある場合、この処理は必ず最初に通る
          If m = LBound(Split(arrstring, vbLf)) + 1 Then
            num1 = InStr(m, data1(i, 2), vbLf) ' 配列 data1 の i 行 2列目(都道府県列)データを、Instr 関数で m(= 1)文字目から区切り文字(vbLf)がある最初の位置の値を変数 num1 に格納
            num2 = InStr(m, data1(i, 3), vbLf) ' 配列 data1 の i 行 3列目(県庁所在地列)データを、Instr 関数で m(= 1)文字目から区切り文字(vbLf)がある最初の位置の値を変数 num2 に格納

            data2(p, 1) = data1(i, 1) ' 配列 data1 の i 行 1列目(地方区分)のデータを、配列 data2 の p 行 1列目に格納
            data2(p, 2) = Left(data1(i, 2), num1 - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Left 関数で、最初の区切り文字位置のひとつ前(num1 - 1)までの文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Left(data1(i, 3), num2 - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Left 関数で、最初の区切り文字位置のひとつ前(num2 - 1)までの文字列を取得、配列 data2 の p 行 3列目に格納
'            data2(p, 2) = Mid(data1(i, 2), m, num1 - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、変数 m 文字目から最初の区切り文字位置のひとつ前(num1 - 1)までの文字列を取得、配列 data2 の p 行 2列目に格納
'            data2(p, 3) = Mid(data1(i, 3), m, num2 - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、変数 m 文字目から最初の区切り文字位置のひとつ前(num2 - 1)までの文字列を取得、配列 data2 の p 行 3列目に格納

            p = p + 1 ' 配列 data2 の p 行をインクリメント(+1)して次の行に指定
          End If

          ' for 文のカウンタ用変数 m が初期値以外かつ最終値以外の場合(Split 関数を使って区切り文字(vbLf)で文字列型変数 arrstring に格納された文字列を分割後、Lbound 関数で要素番号の最小値(必ず 0)+1 以外かつ最大値 +1 以外の場合)
          ' 例としてカウンタ用変数 m が 1 ~ 4 場合 2 と 3 が条件に合致、変数 m が 1 ~ 3 の場合 2 が条件合致、変数 m が 1 ~ 2 の場合はどちらも初期値(要素番号最小値 +1)と最終値(要素番号最大値 +1)のため条件に合致しない
          If m <> LBound(Split(arrstring, vbLf)) + 1 And m <> UBound(Split(arrstring, vbLf)) + 1 Then
            num3 = InStr(num1 + 1, data1(i, 2), vbLf) ' 配列 data1 の i 行 2列目(都道府県列)データを Instr 関数で、変数 num1 に格納されている区切り文字位置の値の次の位置(num1 + 1)から次の区切り文字(vbLf)がある位置の値を変数 num3 に格納
            num4 = InStr(num2 + 1, data1(i, 3), vbLf) ' 配列 data1 の i 行 2列目(県庁所在地)データを Instr 関数で、変数 num1 に格納されている区切り文字位置の値の次の位置(num2 + 1)から次の区切り文字(vbLf)がある位置の値を変数 num4 に格納

            data2(p, 1) = data1(i, 1) ' 配列 data1 の i 行 1列目(地方区分)のデータを、配列 data2 の p 行 1列目に格納
            data2(p, 2) = Mid(data1(i, 2), num1 + 1, num3 - num1 - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、変数 num1 に格納されている区切り文字位置の次の位置(num1 + 1)から次の区切り文字位置のひとつ前までの文字数(num3 - num1 - 1)を指定して文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Mid(data1(i, 3), num2 + 1, num4 - num2 - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、変数 num2 に格納されている区切り文字位置の次の位置(num2 + 1)から次の区切り文字位置のひとつ前までの文字数(num4 - num2 - 1)を指定して文字列を取得、配列 data2 の p 行 3列目に格納

            num1 = num3 ' 配列 data1 の i 行 2列目(都道府県)の区切り文字開始位置の値(num1)を、次の区切り文字位置の値(num3)に更新(複数の区切り文字がある場合の繰り返し処理対応)
            num2 = num4 ' 配列 data1 の i 行 3列目(県庁所在地)の区切り文字開始位置の値(num2)を、次の区切り文字位置の値(num4)に更新(複数の区切り文字がある場合の繰り返し処理対応)

            p = p + 1 ' 配列 data2 の p 行をインクリメント(+1)して次の行に指定
          End If

          ' For 文のカウンタ用変数 m が最終値の場合(Split 関数を使って区切り文字(vbLf)で文字列型変数 arrstring に格納された文字列を分割後、Lbound 関数で要素番号の最大値 +1 の場合)
          ' 例としてカウンタ用変数 m が 1 ~ 3 場合 3 が条件に合致、変数 m が 1 ~ 2 の場合 2 が条件合致
          ' 区切り文字がある場合、この処理は必ず最後に通る
          If m = UBound(Split(arrstring, vbLf)) + 1 Then
            data2(p, 1) = data1(i, 1) ' 配列 data1 の i 行 1列目(地方区分)のデータを、配列 data2 の p 行 1列目に格納
            data2(p, 2) = Mid(data1(i, 2), num1 + 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、変数 num1 に格納されている最後の区切り文字位置の次の位置(num1 + 1)からデータ終端まで文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Mid(data1(i, 3), num2 + 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、変数 num2 に格納されている最後の区切り文字位置の次の位置(num2 + 1)からデータ終端まで文字列を取得、配列 data2 の p 行 3列目に格納

            p = p + 1 ' 配列 data2 の p 行をインクリメント(+1)して次の行に指定
          End If
        Next m

        ' カウンタ用変数 i をインクリメントして配列 data1(i, 1)の次の地方区分行に進む前に、区切り文字位置の値格納用変数すべてを 0 で初期化
        num1 = 0
        num2 = 0
        num3 = 0
        num4 = 0

      End If

    Next i

Case 1 では、InStr・Left(または Mid)関数を使って複数ある区切り文字位置の前後の場所を特定、そこから区切り文字間にある文字列を特定して 先ほど生成した 2次元配列(234~256行目) に代入します。

この処理を行うことで 1つのセルに区切り文字を使って連結された複数の文字列を、行単位で分割することができます。ただし、複数の複雑な判定や、判定に必要な値の格納・更新を頻繁に行うためコードがかなり長くなっています。

これについては Case 2 では値を格納する変数を動的配列(1次元配列)に、Case 3 ではさらに For 文を使って繰り返し処理ができるようにして、コード内容を改良して多少短くなるようにしています。なお、Case 4 については全く別のコード内容となっており、こちらのほうがシンプルですっきりしています。

274行目で 4つの Long 型変数を宣言して 277~280行目で 0 で初期化しています。ここでは都道府県列・県庁所在地列の各文字列の前後にある区切り文字位置を格納するため 4つの変数を用意しています。区切り文字位置は InStr 関数(後述)を使って特定します。

283行目はカウンタ変数 p に初期値として 1 を設定します。このカウンタ変数 p を使って、格納先 2次元配列 data2 の p 行目から順番に、区切り文字間にある都道府県・県庁所在地文字列を代入します。後述する各 If 文の条件式で 2次元配列に区切り文字間にある文字列を格納後、If 文を抜ける前に p = p + 1 でインクリメントして次の 2次元配列の格納先の行番号を指定します。


285行目では For 文とカウンタ変数 i、LBound 関数と UBound 関数を組み合わせて、各地方区分別の区切り文字で連結されたデータ(都道府県と県庁所在地)を格納した 2次元配列 data1 の 1次元(行相当)の最小~最大要素までループさせます。この最初の For 文は 360行目まで続き、この間に様々な判定と処理を行います。

カウンタ変数 i については 2次元配列 data1 の行番号の操作に使います。2次元配列 data2 の行番号の操作ではカウンタ変数 p を使うので明確に使い分けます。カウンタ変数 i は 2次元配列 data1 の各地方区分の行番号を指しているので、カウンタ変数 i は地方区分数ループ処理を行うことになります。

289行目で 262行目で宣言した String 型変数 arrstring に、2次元配列 data1 の i 行 2列目(各地方区分の都道府県)を代入します。この後の If・For 文で変数 arrstring に対して LBound・UBound・Split 関数を使って、区切り文字数を計算・カウントを行い、区切り文字数に応じた処理を実行するのに使います。

ちなみにコメントアウトしている 290行目では変数 arrstring に 2次元配列 data1 の i 行 3列目(各地方区分の県庁所在地)を代入しています。区切り文字数チェック処理data1(i, 2) または data1(i, 3) どちらも同じ区切り文字数が含まれていることを確認しているので、区切り文字数取得が目的である今回の場合、289行目または 290行目どちらを実行しても同じ結果を得られます。

293行目から 360行目の間に If 文による条件分岐に応じた For 文や各種関数を使った処理をしていきます。まずはおおもととなる If・For 文による条件式・繰り返し条件について説明して、そのあと内部の具体的な詳細な処理内容について説明します。


293行目の If 文では、Split 関数で変数 arrstring と区切り文字(vbLf)を指定して、区切られた各文字列を配列として返します。続けて Split 関数で返した配列を Ubound 関数で最大要素番号を返した値を判定します。

293行目の If 文の条件式の意味は変数 arrstring に対して Split・Ubound 関数の結果、0 または -1 を返した場合に 294~301行目の処理を実行します。

どのような条件で変数 arrstring に Split・Ubound 関数を通すと 0 または -1 になるかは次の通りです。

変数 arrstring に区切り文字がない場合(例:北海道地方)は Split・Ubound 関数で 0 を返します。変数 arrstring が Empty(今回は該当するデータはありませんが、仮に何も入っていなかった場合)なら Split・Ubound 関数で -1 を返します。つまり 293行目の条件式で区切り文字があるかどうか判断して、区切り文字がなければ If 文内を処理をします。区切り文字が 1つ以上あれば次の 305行目の If 文で条件分岐します。


305行目の If 文では変数 arrstring に対して Split・Ubound 関数の結果が 0 より大きければ処理をする条件分岐です。293行目の If 文で該当しなかった場合は区切り文字が 1つ以上あるはずなので、305行目の If 文では必ず True 判定になります。


308行目の For 文ではカウンタ変数 m の開始値に 1次元配列 arrstring の最小要素番号(必ず 0)に +1 をしたものを、終了値に同じ 1次元配列 arrstring の最大要素番号に +1 に代入して 350行目までの間をループ処理します。これはカウンタ変数 m を使って、区切り文字間の文字列を抽出(後述)するために使います。

308行目 For 文のカウンタ変数 m の値に応じて、311行目・326行目・343行目にある 3つの各 If 文で条件分岐をして、切り文字間の文字列を抽出する処理を行います。以下、311行目・326行目・343行目の各 If 文による条件分岐について説明します。


最初の 311行目の If 文は、308行目のカウンタ変数 m の開始値を条件式にしています。これにより 311行目の条件式は必ず True になるため、つまり 308行目の For 文の次に 312~321行目にある処理を最初に行うことになります。

続いて 326行目の If 文は 308行目のカウンタ変数 m が開始値以外かつ終了値以外を条件式にしています。True の場合、327~337行目にある処理をします。

例としてカウンタ変数 m が 1 ~ 4 の場合、値が 2 と 3 の時に条件に合致、カウンタ変数 m が 1 ~ 3 の場合、値が 2 の時に条件に合致するので、その場合のみ True となって処理をします。カウンタ変数 m が 1 ~ 2 までの場合はどちらも開始値(要素番号最小値 +1)と終了値(要素番号最大値 +1)のため条件に合致せず処理はしません。

最後の 343行目の If 文は 308行目のカウンタ変数 m の終了値を条件式にしています。True の場合、334~348行目にある処理をします。

例としてカウンタ変数 m が 1 ~ 3 の場合、値が 3 の時に条件に合致、カウンタ変数 m が 1 ~ 2 の場合、値が 2 の時に条件に合致するので、その場合のみ True となって処理をします。つまりカウンタ変数 m が終了値の場合は 343行目の条件式は必ず True になるため、308行目の For 文内では 334~348行目にある処理は最後に行うことになります。


なお、293行目、311行目、326行目、343行目にある 4つの各 If 文内にある処理の最後、301行目・321行目・337行目・348行目でカウンタ変数 p をインクリメントしています。これはそれぞれの If 文で 2次元配列 data2 の p 行目に区切り文字間の文字列(都道府県、県庁所在地)を 1つずつ代入しているので、次の区切り文字間の文字列を格納するためにカウンタ変数 p をインクリメントすることで、2次元配列 data2 の次の代入先 p 行目を指定させるためとなっています。


293行目・311行目・326行目・343行目にある 4つの各 If 文による、切り文字間の文字列を抽出する処理について説明します。


293行目の If 文では区切り文字がない場合に 294~301行目にある処理を行います。1つでも区切り文字があれば処理は行わず、305行目から判定と処理をします。ここでは切り文字間の文字列抽出処理を行う必要がないので、2次元配列に格納してるデータを単純に別の 2次元配列に代入させるだけとなっています。

294行目のカウンタ変数 k で、地方区分と都道府県と県庁所在地を格納した 2次元配列 data1 の 2次元最大要素までループ処理を行い、これを 2次元配列の列番号として扱います。

285行目の For 文にカウンタ変数 i によるループ処理と、283行目のカウンタ変数 p と 301行目・321行目・337行目・348行目でインクリメントしたカウンタ変数 p を 2次元配列の行番号とすることで、data2(p, k) = data1(i, k) の代入式が成立します。


311行目の If 文では必ず True になるので、308行目の For 文に入ってから必ず最初に 312~321行目にある処理を行います。

312~313行目で 274行目で宣言した変数(num1 と num2)に InStr 関数の返り値を代入します。InStr 関数の第 1引数にカウンタ変数 m(値は必ず 1)を、第 2引数に区切り文字列を含む 2次元配列 data1 の i 行 2~3 列目を指定(2列目は都道府県、3列目は県庁所在地)、第 3引数に今回使用している区切り文字である vbLf を指定します。

この InStr 関数と引数を指定することで、2次元配列にある複数の区切り文字を含む文字列内の 最初の区切り文字位置を特定 することができます。

315~317行目では、312~313行目で最初の区切り文字位置を特定した変数(num1 と num2)を使って、先頭から最初の区切り文字の間にある文字列を抽出して 2次元配列 data2 に代入します。

315行目は地方区分名を代入するだけなので、295行目の data2(p, k) = data1(i, k) の k を 1 に書き換えて、data2(p, 1) = data1(i, 1) とすることで 2次元配列 data1 から 2次元配列 data2 へ地方区分名を代入しています。

316~317行目では Left 関数(または Mid 関数)を使うことで、一番最初の区切り文字位置までにある都道府県名・県庁所在地名を 2次元配列 data1 から 2次元配列 data2 へ代入してます。

Left 関数では第 1引数に区切り文字列を含む 2次元配列 data1 の i 行 2~3 列目を指定(312~313行目 InStr関数の第 2引数と同じ)、第 2引数に 312~313行目で InStr 関数の返り値を代入した変数(num1 と num2)に -1 を差し引きます。(-1 を差し引くことで区切り文字位置の一つ手前という意味になる)

これで最初の区切り文字までにある都道府県名・県庁所在地名を抽出することができます。

コメントアウトしている 318~319行目の Mid 関数を使用する場合は、Left 関数の第 2引数を第 3引数へ、第 2引数にカウンタ変数 m を指定することで、Left 関数と同じ結果を得られます。


326行目の If 文では 327~337行目にある処理を行います。ここでは 前後の区切り文字位置を特定してその間にある文字列を抽出 します。複数の区切り文字がある場合は、最初と最後の文字列以外が文字列抽出の対象となるため、繰り返し処理を行うことになります。

これにより 308行目のカウンタ変数 m の開始値と終了値の間にある値が 1つ以上ある場合のみ処理をします。例えばカウンタ変数 m の開始値が 1 で終了値が 10 の場合は 2 ~ 9 の時に処理をします。カウンタ変数 m 開始値が 1、終了値 が 2 の場合は間に値がないのでこのような場合は処理をしないことになります。

326行目の If 文内で処理するには、311行目の If 文内 312~313行目の InStr 関数を使って返り値を代入した変数(num1 と num2)を使います。コード内容については 312~321行目と基本的に同じで、一部変数と引数を変更させたものとなっています。

327~328行目で 274行目で宣言した変数(num3 と num4)に InStr 関数の返り値を代入します。InStr 関数の第 1引数に変数(num1 と num2)を使って +1 を加算(num1 と num2 に格納した区切り文字がある位置の次の位置から)、第 2引数に区切り文字列を含む 2次元配列 data1 の i 行 2~3 列目を指定(2列目は都道府県、3列目は県庁所在地)、第 3引数に今回使用している区切り文字である vbLf を指定します。

この InStr 関数と引数を指定することで、2次元配列にある複数の区切り文字を含む文字列内の、区切り文字位置を格納している変数(num1 と num2)から次の区切り文字位置を特定 することができます。

330行目は 315行目と同じ、2次元配列 data1 から 2次元配列 data2 へ地方区分名を代入しています。

331~332行目では Mid 関数を使用します。第 1引数に区切り文字列を含む 2次元配列 data1 の i 行 2~3 列目を指定(327~328行目の第 2引数と同じ)、第 2引数に 312~313行目で InStr 関数の返り値を代入した変数(num3 と num4)に +1 を加算したものを、第 3引数に区切り文字位置を格納した 327~328行目の変数(num3 と num4)に、ひとつ前の区切り文字位置を格納した変数(num1 と num2)を差し引き、さらに - 1 を差し引きます。

この Mid 関数と引数の指定により 区切り文字前後間にある文字列を抽出 することができます。

334~335行目でひとつ前の区切り文字位置を格納した変数(num1 と num2)に、次の区切り文字位置を格納した変数(num3 と num4)を代入して更新します。これで 331~332行目で文字列抽出後に、区切り文字位置情報を更新することで、繰り返し次の区切り文字間にある文字列を抽出することができるようにしています。


343行目の If 文では必ず True になるので、308行目の For 文に入ったら必ず最後に 334~348行目にある処理を行います。ここでは 最後の区切り文字以降にある文字列を抽出 します。

344行目は 315行目と 330行目と同じ、2次元配列 data1 から 2次元配列 data2 へ地方区分名を代入しています。

345~346行目では Mid 関数を使うことで、一番最後にある区切り文字位置から終端までの都道府県名・県庁所在地名を、2次元配列 data1 から 2次元配列 data2 へ代入してます。

Mid 関数では第 1引数に区切り文字列を含む 2次元配列 data1 の i 行 2~3 列目を指定(331~332行目 Mid 関数の第 1引数と同じ)、第 2引数に 312~313行目または 334~335行目の区切り文字位置格納変数(num1 と num2)に格納した最後の区切り文字位置に +1 加算します。

これで最後の区切り文字から終端までの都道府県名・県庁所在地名を抽出することができます。


308行目の For 文処理を抜けた後、次の地方区分の都道府県・県庁所在地の区切り文字位置格納のため、353~356行目で区切り文字格納変数(num1~num4)を 0 で初期化しています。この初期化はやらなくても大丈夫かと思いますが、念のため初期化しています。

360行目まで進み 285行目の For 文による次のループ処理を開始します。これで次の地方区分に移動して処理を繰り返します。

Case 2 - Case 1 と同じ処理内容、変更点は区切り文字位置の値格納用変数を使わず、代わりに区切り文字位置の値格納用動的配列を使用

  Case 2 ' Case 1 と同じ処理内容、変更点は区切り文字位置の値格納用変数 num1 ~ num4 を使わず、代わりに区切り文字位置の値格納用動的配列 num() を使用

    ' 区切り文字位置の値格納用動的配列 num() を定義して初期値設定
    ReDim num(3) ' 区切り文字位置の値格納用変数 num1 ~ num4 の個数分(全部で 4つ)要素数を定義
    For i = LBound(num) To UBound(num) ' 動的配列の最大要素までループ処理
      num(i) = 0 ' 動的配列 num の i 番目に 0 を設定
    Next i
'    num = Array(0, 0, 0, 0) ' 動的配列と for 文を使わない場合の書き方

    p = 1

    For i = LBound(data1, 1) To UBound(data1, 1)
      arrstring = data1(i, 2)

      If UBound(Split(arrstring, vbLf)) = 0 Or UBound(Split(arrstring, vbLf)) = -1 Then
        For k = LBound(data1, 2) To UBound(data1, 2)
          data2(p, k) = data1(i, k)
        Next k
'        data2(p, 1) = data1(i, 1)
'        data2(p, 2) = data1(i, 2)
'        data2(p, 3) = data1(i, 3)

        p = p + 1
      End If

      If UBound(Split(arrstring, vbLf)) > 0 Then
        For m = LBound(Split(arrstring, vbLf)) + 1 To UBound(Split(arrstring, vbLf)) + 1
          If m = LBound(Split(arrstring, vbLf)) + 1 Then
            num(0) = InStr(m, data1(i, 2), vbLf) ' 配列 data1 の i 行 2列目(都道府県列)データを、Instr 関数で m(= 1)文字目から区切り文字(vbLf)がある最初の位置の値を動的配列 num(0) に格納
            num(1) = InStr(m, data1(i, 3), vbLf) ' 配列 data1 の i 行 3列目(県庁所在地列)データを、Instr 関数で m(= 1)文字目から区切り文字(vbLf)がある最初の位置の値を動的配列 num(1) に格納

            data2(p, 1) = data1(i, 1)
            data2(p, 2) = Left(data1(i, 2), num(0) - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Left 関数で、最初の区切り文字位置のひとつ前(num(0) - 1)までの文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Left(data1(i, 3), num(1) - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Left 関数で、最初の区切り文字位置のひとつ前(num(1) - 1)までの文字列を取得、配列 data2 の p 行 3列目に格納

'            data2(p, 2) = Mid(data1(i, 2), m, num(0) - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、変数 m 文字目から最初の区切り文字位置のひとつ前(num(0) - 1)までの文字列を取得、配列 data2 の p 行 2列目に格納
'            data2(p, 3) = Mid(data1(i, 3), m, num(1) - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、変数 m 文字目から最初の区切り文字位置のひとつ前(num(1) - 1)までの文字列を取得、配列 data2 の p 行 3列目に格納

            p = p + 1
          End If

          If m <> LBound(Split(arrstring, vbLf)) + 1 And m <> UBound(Split(arrstring, vbLf)) + 1 Then
            num(2) = InStr(num(0) + 1, data1(i, 2), vbLf) ' 配列 data1 の i 行 2列目(都道府県列)データを Instr 関数で、動的配列 num(0) に格納されている区切り文字位置の次の位置(num(0) + 1)から次の区切り文字(vbLf)がある位置の値を動的配列 num(2) に格納
            num(3) = InStr(num(1) + 1, data1(i, 3), vbLf) ' 配列 data1 の i 行 2列目(県庁所在地)データを Instr 関数で、動的配列 num(1) に格納されている区切り文字位置の次の位置(num(1) + 1)から次の区切り文字(vbLf)がある位置の値を動的配列 num(3) に格納
            
            data2(p, 1) = data1(i, 1)
            data2(p, 2) = Mid(data1(i, 2), num(0) + 1, num(2) - num(0) - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、動的配列 num(0) に格納されている区切り文字位置の次の位置(num(0) + 1)から次の区切り文字位置のひとつ前までの文字数(num(2) - num(0) - 1)を指定して文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Mid(data1(i, 3), num(1) + 1, num(3) - num(1) - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、動的配列 num(1) に格納されている区切り文字位置の次の位置(num(1) + 1)から次の区切り文字位置のひとつ前までの文字数(num(3) - num(1) - 1)を指定して文字列を取得、配列 data2 の p 行 3列目に格納

            num(0) = num(2) ' 配列 data1 の i 行 2列目(都道府県)の区切り文字開始位置の値(num(0))を、次の区切り文字位置の値(num(2))に更新(複数の区切り文字がある場合の繰り返し処理対応)
            num(1) = num(3) ' 配列 data1 の i 行 3列目(県庁所在地)の区切り文字開始位置の値(num(1))を、次の区切り文字位置の値(num(3))に更新(複数の区切り文字がある場合の繰り返し処理対応)

            p = p + 1
          End If

          If m = UBound(Split(arrstring, vbLf)) + 1 Then
            data2(p, 1) = data1(i, 1)
            data2(p, 2) = Mid(data1(i, 2), num(0) + 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、動的配列 num(0) に格納されている最後の区切り文字位置の次の位置(num(0) + 1)からデータ終端まで文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Mid(data1(i, 3), num(1) + 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、動的配列 num(1) に格納されている最後の区切り文字位置の次の位置(num(1) + 1)からデータ終端まで文字列を取得、配列 data2 の p 行 3列目に格納

            p = p + 1
          End If
        Next m

        ' カウンタ用変数 i をインクリメントして配列 data1(i, 1)の次の地方区分行に進む前に、区切り文字位置の値格納用動的配列すべての要素を for 文を使って 0 で初期化
        For k = LBound(num) To UBound(num) ' 動的配列の最大要素までループ処理
          num(k) = 0 ' 動的配列 num の i 番目に 0 を設定
        Next k
'        num(0) = 0 ' for 文を使わない場合の書き方
'        num(1) = 0 ' for 文を使わない場合の書き方
'        num(2) = 0 ' for 文を使わない場合の書き方
'        num(3) = 0 ' for 文を使わない場合の書き方

      End If

    Next i

Case 2 では Case 1 で使用した区切り文字位置格納用変数(num1~num4)(274~280行目) を、263行目で宣言した動的配列 num に変更しています。それ以外のコードの全体構成は Case 1 とほとんど変わりません。以下、コード内容に変更点があるところを説明します。

動的配列 num を 1次元配列として使い、要素番号を指定して区切り文字位置の値を格納します。

365行目の ReDim ステートメントで動的配列 num の要素数を定義します。Case 1 で使用した変数 num1~num4 の個数に合わせて num(3) と定義しています。

366行目の For 文で 動的配列 num の最大要素までループ処理を行い、367行目で各要素を 0 でまとめて初期化しています。変数 num1~num4 では個別に 0 を代入していたので、For 文を使うことで 1次元配列の各要素をまとめて初期化できます。なお、コメントアウトしている 369行目の内容は For 文を使わない場合の Array 関数を使った配列の初期化方法です。

以降、各行でハイライトされているところでは変数から 1次元配列にコード内容を書き換えています。(num1 →、num(0)、num2 →、num(1)、num3 →、num(2)、num4 →、num(3))

427~429行目でカウンタ変数 k を使った For 文で動的配列 num のすべての要素を 0 でまとめて初期化しています。これは 366~378行目の For 文のカウンタ変数 i から k に変更したもので、カウンタ変数以外は同じループ処理による配列の初期化コードとなっています。

Case 3 - Case 2 と同じ処理内容、変更点は各配列の行・列・要素番号への直接値の指定からカウンタ用変数と For 文を使ってループ処理に変更

  Case 3 ' Case 2 と同じ処理内容、変更点は各配列の行・列・要素番号への直接値の指定からカウンタ用変数 k と For 文を使ってループ処理に変更

    ReDim num(3)
    For i = LBound(num) To UBound(num)
      num(i) = 0
    Next i
'    num = Array(0, 0, 0, 0)

    p = 1

    For i = LBound(data1, 1) To UBound(data1, 1)
      arrstring = data1(i, 2)

      If UBound(Split(arrstring, vbLf)) = 0 Or UBound(Split(arrstring, vbLf)) = -1 Then
        For k = LBound(data1, 2) To UBound(data1, 2)
          data2(p, k) = data1(i, k)
        Next k
'        data2(p, 1) = data1(i, 1)
'        data2(p, 2) = data1(i, 2)
'        data2(p, 3) = data1(i, 3)

        p = p + 1
      End If

      If UBound(Split(arrstring, vbLf)) > 0 Then
        For m = LBound(Split(arrstring, vbLf)) + 1 To UBound(Split(arrstring, vbLf)) + 1
          If m = LBound(Split(arrstring, vbLf)) + 1 Then
            data2(p, 1) = data1(i, 1)

            For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
              num(k - 2) = InStr(m, data1(i, k), vbLf) ' 配列 data1 の i 行 k 列目(都道府県列・県庁所在地)データを、Instr 関数で m(= 1)文字目から区切り文字(vbLf)がある最初の位置の値を動的配列 num(k - 2) に格納
              data2(p, k) = Left(data1(i, k), num(k - 2) - 1) ' 配列 data1 の i 行 k 列目(都道府県・県庁所在地)のデータを Left 関数で、最初の区切り文字位置のひとつ前(num(k - 2) - 1)までの文字列を取得、配列 data2 の p 行 k 列目に格納
'              data2(p, k) = Mid(data1(i, k), m, num(k - 2) - 1) ' 配列 data1 の i 行 k 列目(都道府県・県庁所在地)のデータを Mid 関数で、変数 m 文字目から最初の区切り文字位置のひとつ前(num(k - 2) - 1)までの文字列を取得、配列 data2 の p 行 k 列目に格納
            Next k
'            num(0) = InStr(m, data1(i, 2), vbLf)
'            num(1) = InStr(m, data1(i, 3), vbLf)

'            data2(p, 2) = Left(data1(i, 2), num(0) - 1)
'            data2(p, 3) = Left(data1(i, 3), num(1) - 1)
'            data2(p, 2) = Mid(data1(i, 2), m, num(0) - 1)
'            data2(p, 3) = Mid(data1(i, 3), m, num(1) - 1)

            p = p + 1
          End If

          If m <> LBound(Split(arrstring, vbLf)) + 1 And m <> UBound(Split(arrstring, vbLf)) + 1 Then
            data2(p, 1) = data1(i, 1)

            For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
              num(k) = InStr(num(k - 2) + 1, data1(i, k), vbLf) ' 配列 data1 の i 行 k 列目(都道府県列・県庁所在地)データを Instr 関数で、動的配列 num(k - 2) に格納されている区切り文字位置の次の位置(num(k - 2) + 1)から次の区切り文字(vbLf)がある位置の値を動的配列 num(k) に格納
              data2(p, k) = Mid(data1(i, k), num(k - 2) + 1, num(k) - num(k - 2) - 1) ' 配列 data1 の i 行 k 列目(都道府県・県庁所在地)のデータを Mid 関数で、動的配列 num(k - 2) に格納されている区切り文字位置の次の位置(num(k - 2) + 1)から次の区切り文字位置のひとつ前までの文字数(num(k) - num(k - 2) - 1)を指定して文字列を取得、配列 data2 の p 行 k 列目に格納
              num(k - 2) = num(k) ' 配列 data1 の i 行 k 列目(都道府県・県庁所在地)の区切り文字開始位置の値(num(k))を、次の区切り文字位置の値(num(k - 2))に更新(複数の区切り文字がある場合の繰り返し処理対応)
            Next k
'            num(2) = InStr(num(0) + 1, data1(i, 2), vbLf)
'            num(3) = InStr(num(1) + 1, data1(i, 3), vbLf)

'            data2(p, 2) = Mid(data1(i, 2), num(0) + 1, num(2) - num(0) - 1)
'            data2(p, 3) = Mid(data1(i, 3), num(1) + 1, num(3) - num(1) - 1)

'            num(0) = num(2)
'            num(1) = num(3)

            p = p + 1
          End If

          If m = UBound(Split(arrstring, vbLf)) + 1 Then
            data2(p, 1) = data1(i, 1)

            For k = LBound(data1, 2) + 1 To UBound(data1, 2) ' 2列目から 2次元最大要素までループ処理
              data2(p, k) = Mid(data1(i, k), num(k - 2) + 1) ' 配列 data1 の i 行 k 列目(都道府県・県庁所在地)のデータを Mid 関数で、動的配列 num(k - 2) に格納されている最後の区切り文字位置の次の位置(num(k - 2) + 1)からデータ終端まで文字列を取得、配列 data2 の p 行 k 列目に格納
            Next k
'            data2(p, 2) = Mid(data1(i, 2), num(0) + 1)
'            data2(p, 3) = Mid(data1(i, 3), num(1) + 1)

            p = p + 1
          End If
        Next m

        For k = LBound(num) To UBound(num)
          num(k) = 0
        Next k
'        num(0) = 0
'        num(1) = 0
'        num(2) = 0
'        num(3) = 0

      End If

    Next i

Case 3 では Case 2 のコードをそのまま流用して一部変更しています。

263行目で宣言した動的配列 num の各要素番号を個々に指定して変数と同じような扱いで使用していましたが、それを For 文とカウンタ変数を使って配列の要素番号を操作します。

468行目のカウンタ変数 k の開始値は 2 からとなっているので、469行目の配列 num(k - 2) とすることで最小要素番号を指定して、最初の区切り文字位置を配列に格納しています。

488行目では次の区切り文字位置の格納先を配列 num(k) に指定することで、num(k - 2) とは別の要素番号に格納するようにしています。

490行目の num(k - 2) = num(k) とすることで、For 文内でひとつ前の区切り文字(開始)位置を次の区切り文字位置に更新できます。

以上のようにカウンタ変数とそれに対して値を入れて調整することで、For 文で区切り文字位置を格納する配列の要素番号を操作することができます。

Case 4 - Split 関数で区切られた文字列を 1次元配列に格納、カウンタ用変数と For 文を使って列(縦)方向に 1次元配列から 2次元配列の各要素を代入処理

  Case 4 ' Split 関数で配列に格納した各要素を、インクリメントしたカウンタ変数 s を使って 2次元配列 data2 の行番号を指定して各要素を格納

    Dim tmp As Variant ' Split 関数で返した配列の格納用変数
    Dim s As Long ' 2次元配列 data2 の行番号変数 p 用インクリメント変数

    p = 1
    s = 0 ' 0 で初期化

    For i = LBound(data1, 1) To UBound(data1, 1)
      arrstring = data1(i, 2)

      If UBound(Split(arrstring, vbLf)) = 0 Or UBound(Split(arrstring, vbLf)) = -1 Then
        For k = LBound(data1, 2) To UBound(data1, 2)
          data2(p, k) = data1(i, k)
        Next k
'        data2(p, 1) = data1(i, 1)
'        data2(p, 2) = data1(i, 2)
'        data2(p, 3) = data1(i, 3)

        p = p + 1
      End If

      If UBound(Split(arrstring, vbLf)) > 0 Then

        For k = LBound(data1, 2) + 1 To UBound(data1, 2)
          ' Split 関数の第 1引数に区切り文字列がある 2次元配列を、第 2引数に区切り文字(vbLf)を指定
          ' 1次元配列として返した区切られた各文字列をバリアント型変数 tmp に格納
          tmp = Split(data1(i, k), vbLf)

          ' 分割した都道府県・県庁所在地別の地方区分名を 2次元配列 data2 に格納
          If k = 2 Then ' For 文内で都道府県・県庁所在地別に行分割処理を行う際に地方区分名の代入は 1度だけでいいため、カウンタ変数 k の初期値 2(都道府県列)の時だけ地方区分名を代入処理
            For m = LBound(tmp) To UBound(tmp) ' 1次元配列 tmp の最大要素までループ処理
              data2(p + s, 1) = data1(i, 1) ' 2次元配列 data1 の地方区分名を 2次元配列 data2 に代入、2次元配列 data2 の行番号 p をインクリメントした変数 s を使って行番号指定(ループ開始処理時の変数 s の初期値は 0、ループ処理を抜けたら 0 で初期化)
              s = s + 1 ' 変数 s をインクリメントして次の行番号 p に加算
            Next m

            s = 0 ' 変数 s を 0 で初期化

          End If

          ' 分割した都道府県・県庁所在地名を 2次元配列 data2 に格納
          For m = LBound(tmp) To UBound(tmp) ' 1次元配列 tmp の最大要素までループ処理
            data2(p + s, k) = tmp(m) ' 1次元配列 tmp の都道府県名・県庁所在地名を 2次元配列 data2 に代入、2次元配列 data2 の行番号 p をインクリメントした変数 s を使って行番号指定(ループ開始処理時の変数 s の初期値は 0、ループ処理を抜けたら 0 で初期化)
            s = s + 1 ' 変数 s をインクリメントして次の行番号 p に加算
          Next m

          s = 0 ' 変数 s を 0 で初期化

        Next k

        p = p + UBound(tmp) + 1 ' 配列 data2 の行番号 p に、1次元配列 tmp の最大要素(UBound 関数使用)と 1 を足して次の配列 data2 への代入先行番号を更新(1次元配列 tmp の開始要素番号が 0 からのため + 1 で調整)

      End If

    Next i

Case 4 では各 Case 節(Case 1Case 2Case 3)の大きな処理の流れの部分は流用しつつ、区切り文字間の文字列については違う方法を用いて行分割処理をします。

これまでの各 Case 節では区切り文字の有無を Split 関数で判定し、抽出対象文字列の前後にある区切り文字位置を InStr 関数で求めて、Left・Mid 関数で区切り文字間にある文字列を 1つずつ抽出して行分割をしていました。

この Case 4 では Split 関数で抽出した区切り文字間の文字列を、Left・Mid 関数を使わず直接 2次元配列の列(縦)方向に一気に代入します。(Case 1Case 2Case 3 では行(横)方向への代入処理)

531行目で Split 関数で返した配列を格納する変数を宣言します。532行目で 2次元配列 data2 の行番号変数 p を操作するために使う変数 s を別に用意して、535行目で 0 に初期化しています。

2次元配列 data2 の行番号に変数 p を使っているところは変更ありませんが、Split 関数で抽出した文字列を 2次元配列のどの行番号に代入するかについては、532行目で宣言した変数 s の値をインクリメントして、固定行の変数 p に対して変数 s を加算して調整する形で使用します。

556行目で Split 関数で抽出した区切り文字間の文字列を変数に代入して、1次元配列として扱います。

559行目の If 文の条件式で k = 2 としているのは、For 文内で都道府県・県庁所在地別に行分割処理を行う際に地方区分名の代入は 1度だけでいいため、カウンタ変数 k の初期値 2(都道府県列)の時だけ地方区分名を代入処理(560~563行目)するようにしています。

560行目の For 文で 1次元配列 tmp の最大要素までループ処理を行い、561行目で 2次元配列 data1 の地方区分名を 2次元配列 data2 に代入します。For 文でループ処理している間に 562行目で変数 s のインクリメントを行い、2次元配列 data2 の行番号 p に加算することで次の代入先行番号を指定しています。

ループ開始処理時の変数 s の初期値は 535行目で 0 で最初に初期化を行い、560行目のループ処理を抜けた後に 565行目で再度 0 で初期化しています。


570~575行目は先ほどの 560~565行目と同じコード内容で変数だけ変更しています。ここでは Split 関数で各地方区分から抽出した都道府県名・県庁所在地名を 2次元配列 data2 に一気に代入します。

570行目の For 文で 1次元配列 tmp の最大要素までループ処理を行い、571行目で 1次元配列 tmp(要素番号は 570行目のカウンタ変数 m で指定)に Split 関数で格納された都道府県名・県庁所在地名を 2次元配列 data2 に代入します。For 文でループ処理している間に 572行目で変数 s のインクリメントを行い、2次元配列 data2 の行番号 p に加算することで次の代入先行番号を指定しています。

ループ開始処理時の変数 s の初期値は 0(565行目で 0 に初期化)、570行目のループ処理を抜けた後に 575行目で再度 0 に初期化しています。


553行目の For 文処理(カウンタ変数 k)を抜けた後、579行目で次の地方区分の都道府県・県庁所在地を 2次元配列 data2 に格納する行番号 p の開始値を更新します。

各 Case 節(Case 1Case 2Case 3)では p = p + 1 で行番号変数 p をインクリメントだけして調整していましたが、Case 4 では Split 関数から抽出した 1次元配列 tmp の UBound 関数による最大要素数 UBound(tmp) の値を加えた式 p = p + UBound(tmp) + 1 で調整することで、次の代入先 2次元配列の開始行番号 p を求めることができます。

583行目まで進み 537行目の For 文による次のループ処理を開始します。これで次の地方区分に移動して処理を繰り返します。

Excel VBA コードメモリリーク対策について

X(Twitter) にて教えてもらいましたが、LBound と UBound 関数を使用した VBA コードの書き方によってはメモリリークが起きる可能性があるようです。

ただ、指摘のあった関数による VBA コードのメモリリークについて日本語で言及している情報が少なく、今回公開した VBA コードが原因でメモリリークが起きるかどうか確認できていません。(こちらで単純にメモリリークに気づいていないというのもあります)

X(Twitter) で紹介してもらった こちらのサイト ではメモリリークする・しないコードの書き方が紹介されています。以下のセクションではこの書き方にならって、コード内容を書き直したメモリリーク対策版 VBA コードを公開します。

メモリリークが起きないとされているコード内容に修正しただけなので、実際にメモリリークが起きないかどうかまでは確認していません。

基本的に関数の返り値を一度変数に格納して、その変数を使用する方法に書き換えた内容となっています。各コードについて元の VBA コードから追加・変更した箇所をハイライトで表示しています。

区切り文字で文字列が連結されたセルからグループ別に行分割処理 VBA サンプルコード メモリリーク対策版

Option Explicit

Sub SplitRowsCells1FixMemoryLeaks1() ' メモリリーク対策版
  ' 地方区分を基準としてグループ化したシート「地方区分グループ化文字列連結」をシート「地方区分都道府県県庁所在地リスト」に戻す処理
  ' 1行に文字列を連結した都道府県・県庁所在地の文字列を地方区分別に行分割

  ' 実行速度計測開始
  Dim starttime As Double
  starttime = Timer

' ----------

  ' カウンタ用変数(一見見分けにくい文字同士を組み合わせない形、i と j、m と n、o(オー) と 0(ゼロ))
  Dim i As Long, k As Long, m As Long, p As Long

' ----------

  ' シート格納用オブジェクト変数
  Dim ws1 As Worksheet, ws2 As Worksheet, ws3 As Worksheet

  ' オブジェクト変数にシートセット
  Set ws1 = ThisWorkbook.Worksheets("地方区分グループ化文字列連結") ' セル分割対象シートをオブジェクト変数にセット
  Set ws2 = ThisWorkbook.Worksheets("地方区分別行分割") ' セル分割後データ貼り付け先シートをオブジェクト変数にセット
'  Set ws3 = ThisWorkbook.Worksheets("temp") ' 一致したデータ出力先テスト用シート

' ----------

  ' 最終行取得用変数
  Dim maxrow1 As Long

  ' シート最終行取得して変数に格納
  maxrow1 = ws1.Cells(Rows.Count, "A").End(xlUp).row

  ' 最終列取得用変数
  Dim maxcol1 As Long

  ' シートの最終列取得して変数に格納
  maxcol1 = ws1.Cells(1, Columns.Count).End(xlToLeft).Column

' ----------

  ' シートの指定したセル範囲を配列として格納する動的配列
  Dim data1() As Variant

  ' シートの指定した範囲内セルを配列として動的配列に格納
  data1 = ws1.Range(ws1.Cells(2, 1), ws1.Cells(maxrow1, maxcol1)).Value

  ' Range オブジェクトを受け取り、2次元配列で返す自作関数 GetArrFromRange
'  data1 = GetArrFromRange.GetArrFromRange(ws1.Range(ws1.Cells(2, 1), ws1.Cells(maxrow1, maxcol1)))

  ' LBound・UBound 関数格納用変数と代入(メモリリーク対策)
  Dim LB_data1_1D As Variant, UB_data1_1D As Variant
  Dim LB_data1_2D As Variant, UB_data1_2D As Variant
  LB_data1_1D = LBound(data1, 1)
  UB_data1_1D = UBound(data1, 1)
  LB_data1_2D = LBound(data1, 2)
  UB_data1_2D = UBound(data1, 2)

' ----------

  ' 都道府県列と県庁所在地列、両列の区切り文字数チェック処理(区切り文字数が一致しない場合処理終了)

  ' 区切り文字数カウント用配列宣言
  Dim sumdelimiter() As Variant ' 区切り文字数合計用配列
  Dim cntdelimiter() As Variant ' 1セルに含まれる区切り文字数格納用配列

  ' LBound・UBound 関数格納用変数(メモリリーク対策)
  Dim LBound_sumdelimiter As Variant, UBound_sumdelimiter As Variant

  ' 区切り文字数合計を格納する都道府県・県庁所在地列の動的配列を作成
  ReDim sumdelimiter(1) ' sumdelimiter(0) - 都道府県列区切り文字数合計、sumdelimiter(1) - 県庁所在地列区切り文字数合計

  ' LBound・UBound 関数格納用変数と代入(メモリリーク対策)
  Dim LB_sumdelimiter As Variant, UB_sumdelimiter As Variant
  LB_sumdelimiter = LBound(sumdelimiter)
  UB_sumdelimiter = UBound(sumdelimiter)

  For i = LB_sumdelimiter To UB_sumdelimiter
    sumdelimiter(i) = 0 ' 初期値 0 設定
  Next i

  ' LBound・UBound 関数格納用変数(メモリリーク対策)
  Dim LBound_cntdelimiter As Variant, UBound_cntdelimiter As Variant

  ' 1セルに含まれる区切り文字数を格納する都道府県・県庁所在地列の動的配列を作成
  ReDim cntdelimiter(1) ' sumdelimiter(0) - 1セルに含まれる都道府県列区切り文字数格納、sumdelimiter(1) - 1セルに含まれる県庁所在地列区切り文字数格納

  ' LBound・UBound 関数格納用変数と代入(メモリリーク対策)
  Dim LB_cntdelimiter As Variant, UB_cntdelimiter As Variant
  LB_cntdelimiter = LBound(cntdelimiter)
  UB_cntdelimiter = UBound(cntdelimiter)

  For i = LB_cntdelimiter To UB_cntdelimiter
    cntdelimiter(i) = 0 ' 初期値 0 設定
  Next i

  ' Array 関数を使って配列の各要素に初期値 0 設定(動的配列(ReDim)や For 文を使わない場合)
'  sumdelimiter = Array(0, 0)
'  cntdelimiter = Array(0, 0)

  ' Select Case ステートメント用変数宣言
  Dim val1 As Long
  val1 = 1 ' Select Case ステートメント Case 1 ~ Case 4 まで処理を用意、1 ~ 4 のいずれかの値を指定

  ' 変数 val1 の値に応じて Case 1 ~ Case 4 のいずれかの処理を実行
  Select Case val1

  ' Split・UBound 関数格納用変数(メモリリーク対策)
  Dim Split_data1_i_k_vbLf As Variant ' Split_data1_i_k_vbLf = Split(data1(i, k), vbLf)
  Dim UB_Split_data1_i_k_vbLf As Variant ' UB_Split_data1_i_k_vbLf = UBound(Split_data1_i_k_vbLf)

  Case 1 ' Len 関数と Len 関数+ Replace 関数を使って文字数の差分から区切り文字数を計算・合計

    For i = LB_data1_1D To UB_data1_1D ' 1次元最大要素までループ処理
      For k = LB_data1_2D + 1 To UB_data1_2D ' 2列目から 2次元最大要素までループ処理
        ' 配列 data1 の i 行 k 列目の文字数を Len 関数でカウント(区切り文字(vbLf)削除前文字数)
        ' Replace 関数で配列 data1 の i 行 k 列目の区切り文字(vbLf)を "" で削除して Len 関数でカウント(区切り文字(vbLf)削除後文字数)
        ' 区切り文字(vbLf)削除前文字数から区切り文字(vbLf)削除後文字数を差し引き区切り文字数をカウントして、配列 cntdelimiter(k - 2) に代入
        cntdelimiter(k - 2) = Len(data1(i, k)) - Len(Replace(data1(i, k), vbLf, ""))
        ' 配列 sumdelimiter(k - 2) で区切り文字数 cntdelimiter(k - 2) を合計
        sumdelimiter(k - 2) = sumdelimiter(k - 2) + cntdelimiter(k - 2)
      Next k

      ' cntdelimiter(0)(都道府県列)と cntdelimiter(1)(県庁所在地列)の値(区切り文字数)が一致しない場合 Sub プロシージャー終了
      If cntdelimiter(0) <> cntdelimiter(1) Then
        MsgBox "地方区分「" & data1(i, 1) & "」の区切り文字数が一致しないため処理を終了します" & vbCrLf & _
        "都道府県列区切り文字数「" & cntdelimiter(0) & "」、県庁所在地列区切り文字数「" & cntdelimiter(1) & "」"
        Exit Sub
      End If

    Next i

  Case 2 ' Case 1 の 2行の区切り文字数計算式と合計式を 1行にまとめ

    For i = LB_data1_1D To UB_data1_1D ' 1次元最大要素までループ処理
      For k = LB_data1_2D + 1 To UB_data1_2D ' 2列目から 2次元最大要素までループ処理
        ' cntdelimiter(k - 2) = Len(data1(i, k)) - Len(Replace(data1(i, k), vbLf, ""))
        ' sumdelimiter(k - 2) = sumdelimiter(k - 2) + cntdelimiter(k - 2)
        ' 2行の計算式を 1行にまとめ
        sumdelimiter(k - 2) = sumdelimiter(k - 2) + (Len(data1(i, k)) - Len(Replace(data1(i, k), vbLf, "")))
      Next k
    Next i

  Case 3 ' Split 関数で区切り文字で配列に格納された文字列を分割、Ubound 関数で要素番号の最大値を返して区切り文字数を計算・合計

    For i = LB_data1_1D To UB_data1_1D ' 1次元最大要素までループ処理
      For k = LB_data1_2D + 1 To UB_data1_2D ' 2列目から 2次元最大要素までループ処理

        ' Split・UBound 関数格納用変数へ代入(メモリリーク対策)
        Split_data1_i_k_vbLf = Split(data1(i, k), vbLf)
        UB_Split_data1_i_k_vbLf = UBound(Split_data1_i_k_vbLf)
        
        If UB_Split_data1_i_k_vbLf = -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty で Ubound・Split 関数で -1 を返す場合
          cntdelimiter(k - 2) = 0 ' 区切り文字がないため区切り文字数格納用配列 cntdelimiter(k - 2) に 0 を代入
        ElseIf UB_Split_data1_i_k_vbLf <> -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty ではない場合
          cntdelimiter(k - 2) = UB_Split_data1_i_k_vbLf ' Ubound・Split 関数結果を配列 cntdelimiter(k - 2)に代入
        End If
        sumdelimiter(k - 2) = sumdelimiter(k - 2) + cntdelimiter(k - 2) ' 区切り文字数格納用配列 cntdelimiter(k - 2) を区切り文字数合計用配列 sumdelimiter(k - 2)に加算して格納
      Next k

      ' cntdelimiter(0)(都道府県列)と cntdelimiter(1)(県庁所在地列)の値(区切り文字数)が一致しない場合 Sub プロシージャー終了
      If cntdelimiter(0) <> cntdelimiter(1) Then
        MsgBox "地方区分「" & data1(i, 1) & "」の区切り文字数が一致しないため処理を終了します" & vbCrLf & _
        "都道府県列区切り文字数「" & cntdelimiter(0) & "」、県庁所在地列区切り文字数「" & cntdelimiter(1) & "」"
        Exit Sub
      End If

    Next i

  Case 4 ' Case 3 とほぼ同じ処理内容で区切り文字数格納用配列 cntdelimiter(k - 2) を使わずに、Ubound・Split 関数の結果と合計用配列 sumdelimiter(k - 2) を使って計算・合計

    For i = LB_data1_1D To UB_data1_1D ' 1次元最大要素までループ処理
      For k = LB_data1_2D + 1 To UB_data1_2D ' 2列目から 2次元最大要素までループ処理

        ' Split・UBound 関数格納用変数へ代入(メモリリーク対策)
        Split_data1_i_k_vbLf = Split(data1(i, k), vbLf)
        UB_Split_data1_i_k_vbLf = UBound(Split_data1_i_k_vbLf)

        If UB_Split_data1_i_k_vbLf = -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty で Ubound・Split 関数で -1 を返す場合
          sumdelimiter(k - 2) = sumdelimiter(k - 2) ' 区切り文字がないため合計用配列 sumdelimiter(k - 2) に sumdelimiter(k - 2) を代入(変更なし)
        ElseIf UB_Split_data1_i_k_vbLf <> -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty ではない場合
          sumdelimiter(k - 2) = sumdelimiter(k - 2) + UB_Split_data1_i_k_vbLf ' 区切り文字数合計用配列 sumdelimiter(k - 2) と Ubound・Split 関数の結果を使って計算・合計
        End If
      Next k
    Next i

  Case Else ' エラー処理(Sub プロシージャー終了)
  
    MsgBox "変数 val1 に指定された値(1~4)以外の " & val1 & " が代入されているため処理を終了します"
    Exit Sub

  End Select

  ' 区切り文字数合計用配列 sumdelimiter(0)(都道府県列)と sumdelimiter(1)(県庁所在地列)の値をイミディエイトウィンドウに表示(デバッグ用)
  Debug.Print sumdelimiter(0) & "," & sumdelimiter(1)

  ' sumdelimiter(0)(都道府県列)と sumdelimiter(1)(県庁所在地列)の値(区切り文字数)が一致しない場合 Sub プロシージャー終了
  If sumdelimiter(0) <> sumdelimiter(1) Then
    MsgBox "区切り文字数合計が一致しないため処理を終了します" & vbCrLf & _
    "都道府県列区切り文字数合計「" & sumdelimiter(0) & "」、県庁所在地列区切り文字数合計「" & sumdelimiter(1) & "」"
    Exit Sub
  End If

' ----------

  ' 都道府県・県庁所在地列カウント処理(区切り文字数チェック処理をクリアできれば都道府県・県庁所在地ともに必ず 47 になる)
  ' ここの処理結果で配列 sumstring()に格納した値(47)を使って、次に区切り文字から分割した地方区分別の都道府県・県庁所在地を格納する配列を作成

  ' 都道府県・県庁所在地列カウント用配列宣言
  Dim sumstring() As Variant ' 都道府県・県庁所在地数合計用配列
  Dim cntstring() As Variant ' 1セルに含まれる都道府県・県庁所在地数格納用配列

  ' 地名数合計を格納する都道府県・県庁所在地列の動的配列を作成
  ReDim sumstring(1) ' sumstring(0) - 都道府県数合計、sumstring(1) - 県庁所在地数合計

  ' LBound・UBound 関数格納用変数と代入(メモリリーク対策)
  Dim LB_sumstring As Variant, UB_sumstring As Variant
  LB_sumstring = LBound(sumstring)
  UB_sumstring = UBound(sumstring)

  For i = LB_sumstring To UB_sumstring
    sumstring(i) = 0 ' 初期値 0 設定
  Next i

  ' 1セルに含まれる地名数を格納する都道府県・県庁所在地列の動的配列を作成
  ReDim cntstring(1) ' cntstring(0) - 1セルに含まれる都道府県数格納、cntstring(1) - 1セルに含まれる県庁所在地数格納

  ' LBound・UBound 関数格納用変数と代入(メモリリーク対策)
  Dim LB_cntstring As Variant, UB_cntstring As Variant
  LB_cntstring = LBound(cntstring)
  UB_cntstring = UBound(cntstring)

  For i = LB_cntstring To UB_cntstring
    cntstring(i) = 0 ' 初期値 0 設定
  Next i

  ' Array 関数を使って配列の各要素に初期値 0 設定(動的配列(ReDim)や For 文を使わない)
'  sumstring = Array(0, 0)
'  cntstring = Array(0, 0)

  ' Select Case ステートメント用変数宣言
  Dim val2 As Long
  val2 = 1 ' Select Case ステートメント Case 1 と Case 2 の処理を用意、1~2 のいずれかの値を指定

  ' 変数 val2 の値に応じて Case 1 か Case 2 のいずれかの処理を実行
  Select Case val2

  Case 1 ' Split 関数で区切り文字で配列に格納された文字列を分割、Ubound 関数で要素番号の最大値に +1 して都道府県・県庁所在地数を計算・合計

    For i = LB_data1_1D To UB_data1_1D ' 1次元最大要素までループ処理
      For k = LB_data1_2D + 1 To UB_data1_2D ' 2列目から 2次元最大要素までループ処理

        ' Split・UBound 関数格納用変数へ代入(メモリリーク対策)
        Split_data1_i_k_vbLf = Split(data1(i, k), vbLf)
        UB_Split_data1_i_k_vbLf = UBound(Split_data1_i_k_vbLf)

        If UB_Split_data1_i_k_vbLf = -1 Then ' Ubound・Split 関数結果で区切り文字がない場合 -1 を返す時の処理
          cntstring(k - 2) = 1 ' 都道府県・県庁所在地数格納用配列 cntstring(k - 2) に 1 を代入(全国都道府県・県庁所在地数帳尻合わせのため)
        ElseIf UB_Split_data1_i_k_vbLf <> -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty ではない場合
          cntstring(k - 2) = UB_Split_data1_i_k_vbLf + 1 ' Ubound・Split 関数結果を配列 cntstring(k - 2)に代入
        End If
        sumstring(k - 2) = sumstring(k - 2) + cntstring(k - 2) ' 都道府県・県庁所在地数格納用配列 cntstring(k - 2) を都道府県・県庁所在地数合計用配列 sumstring(k - 2)に加算して格納
      Next k
    Next i

  Case 2 ' Case 1 の処理内容で都道府県・県庁所在地数格納用配列 cntstring(k - 2) を使わずに、Ubound・Split 関数の結果と合計用配列 sumstring(k - 2) を使って計算・合計

    For i = LB_data1_1D To UB_data1_1D ' 1次元最大要素までループ処理
      For k = LB_data1_2D + 1 To UB_data1_2D ' 2列目から 2次元最大要素までループ処理

        ' Split・UBound 関数格納用変数へ代入(メモリリーク対策)
        Split_data1_i_k_vbLf = Split(data1(i, k), vbLf)
        UB_Split_data1_i_k_vbLf = UBound(Split_data1_i_k_vbLf)

        If UB_Split_data1_i_k_vbLf = -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty で Ubound・Split 関数で -1 を返す場合
          sumstring(k - 2) = sumstring(k - 2) + 1 ' 都道府県・県庁所在地数合計用配列 sumstring(k - 2) に 1 を足して sumstring(k - 2) に代入(全国都道府県・県庁所在地数帳尻合わせのため)
        ElseIf UB_Split_data1_i_k_vbLf <> -1 Then ' 配列 data1 の i 行 k 列目のデータが Empty ではない場合
          sumstring(k - 2) = sumstring(k - 2) + UB_Split_data1_i_k_vbLf + 1 ' 都道府県・県庁所在地数合計用配列 sumstring(k - 2) と Ubound・Split 関数の結果を使って計算・合計
        End If
      Next k
    Next i

  Case Else ' エラー処理(Sub プロシージャー終了)
  
    MsgBox "変数 val2 に指定された値(1~2)以外の " & val2 & " が代入されているため処理を終了します"
    Exit Sub

  End Select

  ' 都道府県・県庁所在地数合計用配列 sumstring(0)(都道府県列)と sumstring(1)(県庁所在地列)の値をイミディエイトウィンドウに表示(デバッグ用)
  Debug.Print sumstring(0) & "," & sumstring(1)

' ----------

  ' シートの指定したセル範囲を配列として格納する動的配列
  Dim data2() As Variant

  ' シートの指定した範囲内セルを配列として動的配列に格納
  ' 終点セルの行は都道府県・県庁所在地数合計用配列 sumstring(0) または sumstring(1) に + 1 で調整(どちらも値は 47)
  data2 = ws1.Range(ws1.Cells(2, LB_data1_1D), ws1.Cells(sumstring(0) + 1, UB_data1_2D)).Value
'  data2 = ws1.Range(ws1.Cells(2, LB_data1_1D), ws1.Cells(sumstring(1) + 1, UB_data1_2D)).Value

  ' Range オブジェクトを受け取り、2次元配列で返す自作関数 GetArrFromRange
'  data2 = GetArrFromRange.GetArrFromRange(ws1.Range(ws1.Cells(2, LB_data1_1D), ws1.Cells(sumstring(0) + 1, UB_data1_1D)))
'  data2 = GetArrFromRange.GetArrFromRange(ws1.Range(ws1.Cells(2, LB_data1_2D), ws1.Cells(sumstring(1) + 1, UB_data1_2D)))

  ' LBound・UBound 関数格納用変数と代入(メモリリーク対策)
  Dim LB_data2_1D As Variant, UB_data2_1D As Variant
  Dim LB_data2_2D As Variant, UB_data2_2D As Variant
  LB_data2_1D = LBound(data2, 1)
  UB_data2_1D = UBound(data2, 1)
  LB_data2_2D = LBound(data2, 2)
  UB_data2_2D = UBound(data2, 2)

  ' 地方区分・都道府県・県庁所在地格納用 2次元配列の最大要素まで Empty で初期化(繰り返し(やり直し)処理に対応)
  For i = LB_data2_1D To UB_data2_1D ' 1次元最大要素までループ処理
    For k = LB_data2_2D To UB_data2_2D ' 2次元最大要素までループ処理
      data2(i, k) = Empty ' 配列に Empty を代入して初期化
    Next k
'    data2(i, 1) = Empty ' for 文を使わない場合の書き方
'    data2(i, 2) = Empty ' for 文を使わない場合の書き方
'    data2(i, 3) = Empty ' for 文を使わない場合の書き方
  Next i

  ' Redim ステートメントを使った 2次元配列の最大要素までの初期化
'  ReDim data2(1 To UB_data2_1D, 1 To UB_data2_2D)

' ----------

  ' 都道府県・県庁所在地列の区切り文字間にある各地名を順番に分割して抽出、地方区分別に配列の各行列に代入(区切り文字で連結された文字列を地方区分別に分割)

  Dim arrstring As String ' 区切り文字位置特定用文字列型変数宣言
  Dim num() As Variant ' 区切り文字位置の値格納用動的配列宣言、Select Case ステートメント Case 2 と Case 3 で使用

  ' Select Case ステートメント用変数宣言
  Dim val3 As Long
  val3 = 4 ' Select Case ステートメント Case 1 ~ Case 4 の処理を用意、1 ~ 4 のいずれかの値を指定

  ' 変数 val3 の値に応じて Case 1 ~ Case 4 のいずれかの処理を実行
  Select Case val3

  ' Split・LBound・UBound 関数格納用変数(メモリリーク対策)
  Dim Split_arrstring_vbLf As Variant ' Split_arrstring_vbLf = Split(arrstring, vbLf)
  Dim LB_Split_arrstring_vbLf As Variant ' LB_Split_arrstring_vbLf = LBound(Split_arrstring_vbLf)
  Dim UB_Split_arrstring_vbLf As Variant ' UB_Split_arrstring_vbLf = UBound(Split_arrstring_vbLf)
  Dim LB_num As Variant ' LB_num = LBound(num)
  Dim UB_num As Variant ' UB_num = UBound(num)

  Case 1 ' 変数 num1 ~ num4 に区切り文字位置の値を代入して InStr・Left(または Mid)関数を使って区切り文字位置を特定、区切り文字間にある文字列を配列に代入

    Dim num1 As Long, num2 As Long, num3 As Long, num4 As Long ' 区切り文字位置の値格納用変数宣言

    ' 区切り文字位置の値格納用変数を 0 で初期化
    num1 = 0 ' 都道府県列の各セル区切り文字がある最初の文字位置格納用変数(複数の区切り文字がある場合、num1 の文字位置から次の区切り文字がある文字位置(変数 num3)を格納して更新)
    num2 = 0 ' 県庁所在地列の各セル区切り文字がある最初の文字位置格納用変数(複数の区切り文字がある場合、num2 の文字位置から次の区切り文字がある文字位置(変数 num4)を格納して更新)
    num3 = 0 ' 都道府県列の区切り文字位置を格納した変数 num1 を基準にして、次の区切り文字がある位置格納用変数
    num4 = 0 ' 県庁所在地列の区切り文字位置を格納した変数 num3 を基準にして、次の区切り文字がある位置格納用変数

    ' カウンタ用変数 p を使って配列 data2 の p 行に(区切り文字間にある)都道府県・県庁所在地文字列を代入
    p = 1 ' 初期値として 1(行目)を設定、各 If 文の条件式で処理後、最後に p = p + 1 でインクリメントして次の行に指定

    For i = LB_data1_1D To UB_data1_1D ' 1次元最大要素までループ処理
      ' 配列 data1 の i 行 2列目または 3列目のデータを文字列型変数 arrstring に代入
      ' この後の If・For 文で文字列型変数 arrstring に対して LBound・UBound・Split 関数を使い、区切り文字数を計算・カウント、区切り文字数に応じた処理を実行
      ' 区切り文字数取得が目的のため data1(i, 2) または data1(i, 3) のどちらかだけでよい
      arrstring = data1(i, 2)
'      arrstring = data1(i, 3)

      ' Split・LBound・UBound 関数格納用変数へ代入(メモリリーク対策)
      Split_arrstring_vbLf = Split(arrstring, vbLf)
      LB_Split_arrstring_vbLf = LBound(Split_arrstring_vbLf)
      UB_Split_arrstring_vbLf = UBound(Split_arrstring_vbLf)

      ' 文字列型変数 arrstring に区切り文字がない場合は Ubound・Split 関数で 0 を返す、または Empty なら Ubound・Split 関数で -1 を返す場合の処理
      If UB_Split_arrstring_vbLf = 0 Or UB_Split_arrstring_vbLf = -1 Then
        For k = LB_data1_2D To UB_data1_2D ' 2次元最大要素までループ処理
          data2(p, k) = data1(i, k) ' 配列 data1 の i 行 k 列目のデータを、配列 data2 の p 行 k 列目に代入(区切り文字間の文字抽出処理不要)
        Next k
'        data2(p, 1) = data1(i, 1) ' for 文を使わない場合の書き方
'        data2(p, 2) = data1(i, 2) ' for 文を使わない場合の書き方
'        data2(p, 3) = data1(i, 3) ' for 文を使わない場合の書き方

        p = p + 1 ' 配列 data2 の p 行をインクリメント(+1)して次の行に指定
      End If

      ' 文字列型変数 arrstring に区切り文字がある場合の処理
      If UB_Split_arrstring_vbLf > 0 Then
        ' Split 関数を使って区切り文字(vbLf)で文字列型変数 arrstring に格納された文字列を分割、Lbound・Ubound 関数で要素番号の最小値(必ず 0)と最大値を返してそれぞれ +1 を計算
        ' 区切り文字間の文字列を抽出するため、For 文で最小値(必ず 1)と最大値をカウンタ用変数 m に代入してループ処理
        For m = LB_Split_arrstring_vbLf + 1 To UB_Split_arrstring_vbLf + 1
          ' For 文のカウンタ用変数 m が初期値の場合(Split 関数を使って区切り文字(vbLf)で文字列型変数 arrstring に格納された文字列を分割後、Lbound 関数で要素番号の最小値(必ず 0)+1 の場合)
          ' 区切り文字がある場合、この処理は必ず最初に通る
          If m = LB_Split_arrstring_vbLf + 1 Then
            num1 = InStr(m, data1(i, 2), vbLf) ' 配列 data1 の i 行 2列目(都道府県列)データを、Instr 関数で m(= 1)文字目から区切り文字(vbLf)がある最初の位置の値を変数 num1 に格納
            num2 = InStr(m, data1(i, 3), vbLf) ' 配列 data1 の i 行 3列目(県庁所在地列)データを、Instr 関数で m(= 1)文字目から区切り文字(vbLf)がある最初の位置の値を変数 num2 に格納

            data2(p, 1) = data1(i, 1) ' 配列 data1 の i 行 1列目(地方区分)のデータを、配列 data2 の p 行 1列目に格納
            data2(p, 2) = Left(data1(i, 2), num1 - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Left 関数で、最初の区切り文字位置のひとつ前(num1 - 1)までの文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Left(data1(i, 3), num2 - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Left 関数で、最初の区切り文字位置のひとつ前(num2 - 1)までの文字列を取得、配列 data2 の p 行 3列目に格納
'            data2(p, 2) = Mid(data1(i, 2), m, num1 - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、変数 m 文字目から最初の区切り文字位置のひとつ前(num1 - 1)までの文字列を取得、配列 data2 の p 行 2列目に格納
'            data2(p, 3) = Mid(data1(i, 3), m, num2 - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、変数 m 文字目から最初の区切り文字位置のひとつ前(num2 - 1)までの文字列を取得、配列 data2 の p 行 3列目に格納

            p = p + 1 ' 配列 data2 の p 行をインクリメント(+1)して次の行に指定
          End If

          ' for 文のカウンタ用変数 m が初期値以外かつ最終値以外の場合(Split 関数を使って区切り文字(vbLf)で文字列型変数 arrstring に格納された文字列を分割後、Lbound 関数で要素番号の最小値(必ず 0)+1 以外かつ最大値 +1 以外の場合)
          ' 例としてカウンタ用変数 m が 1 ~ 4 場合 2 と 3 が条件に合致、変数 m が 1 ~ 3 の場合 2 が条件合致、変数 m が 1 ~ 2 の場合はどちらも初期値(要素番号最小値 +1)と最終値(要素番号最大値 +1)のため条件に合致しない
          If m <> LB_Split_arrstring_vbLf + 1 And m <> UB_Split_arrstring_vbLf + 1 Then
            num3 = InStr(num1 + 1, data1(i, 2), vbLf) ' 配列 data1 の i 行 2列目(都道府県列)データを Instr 関数で、変数 num1 に格納されている区切り文字位置の値の次の位置(num1 + 1)から次の区切り文字(vbLf)がある位置の値を変数 num3 に格納
            num4 = InStr(num2 + 1, data1(i, 3), vbLf) ' 配列 data1 の i 行 2列目(県庁所在地)データを Instr 関数で、変数 num1 に格納されている区切り文字位置の値の次の位置(num2 + 1)から次の区切り文字(vbLf)がある位置の値を変数 num4 に格納

            data2(p, 1) = data1(i, 1) ' 配列 data1 の i 行 1列目(地方区分)のデータを、配列 data2 の p 行 1列目に格納
            data2(p, 2) = Mid(data1(i, 2), num1 + 1, num3 - num1 - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、変数 num1 に格納されている区切り文字位置の次の位置(num1 + 1)から次の区切り文字位置のひとつ前までの文字数(num3 - num1 - 1)を指定して文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Mid(data1(i, 3), num2 + 1, num4 - num2 - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、変数 num2 に格納されている区切り文字位置の次の位置(num2 + 1)から次の区切り文字位置のひとつ前までの文字数(num4 - num2 - 1)を指定して文字列を取得、配列 data2 の p 行 3列目に格納

            num1 = num3 ' 配列 data1 の i 行 2列目(都道府県)の区切り文字開始位置の値(num1)を、次の区切り文字位置の値(num3)に更新(複数の区切り文字がある場合の繰り返し処理対応)
            num2 = num4 ' 配列 data1 の i 行 3列目(県庁所在地)の区切り文字開始位置の値(num2)を、次の区切り文字位置の値(num4)に更新(複数の区切り文字がある場合の繰り返し処理対応)

            p = p + 1 ' 配列 data2 の p 行をインクリメント(+1)して次の行に指定
          End If

          ' For 文のカウンタ用変数 m が最終値の場合(Split 関数を使って区切り文字(vbLf)で文字列型変数 arrstring に格納された文字列を分割後、Lbound 関数で要素番号の最大値 +1 の場合)
          ' 例としてカウンタ用変数 m が 1 ~ 3 場合 3 が条件に合致、変数 m が 1 ~ 2 の場合 2 が条件合致
          ' 区切り文字がある場合、この処理は必ず最後に通る
          If m = UB_Split_arrstring_vbLf + 1 Then
            data2(p, 1) = data1(i, 1) ' 配列 data1 の i 行 1列目(地方区分)のデータを、配列 data2 の p 行 1列目に格納
            data2(p, 2) = Mid(data1(i, 2), num1 + 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、変数 num1 に格納されている最後の区切り文字位置の次の位置(num1 + 1)からデータ終端まで文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Mid(data1(i, 3), num2 + 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、変数 num2 に格納されている最後の区切り文字位置の次の位置(num2 + 1)からデータ終端まで文字列を取得、配列 data2 の p 行 3列目に格納

            p = p + 1 ' 配列 data2 の p 行をインクリメント(+1)して次の行に指定
          End If
        Next m

        ' カウンタ用変数 i をインクリメントして配列 data1(i, 1)の次の地方区分行に進む前に、区切り文字位置の値格納用変数すべてを 0 で初期化
        num1 = 0
        num2 = 0
        num3 = 0
        num4 = 0

      End If

    Next i

  Case 2 ' Case 1 と同じ処理内容、変更点は区切り文字位置の値格納用変数 num1 ~ num4 を使わず、代わりに区切り文字位置の値格納用動的配列 num() を使用

    ' 区切り文字位置の値格納用動的配列 num() を定義して初期値設定
    ReDim num(3) ' 区切り文字位置の値格納用変数 num1 ~ num4 の個数分(全部で 4つ)要素数を定義

    ' LBound・UBound 関数格納用変数へ代入(メモリリーク対策)
    LB_num = LBound(num)
    UB_num = UBound(num)

    For i = LB_num To UB_num ' 動的配列の最大要素までループ処理
      num(i) = 0 ' 動的配列 num の i 番目に 0 を設定
    Next i
'    num = Array(0, 0, 0, 0) ' 動的配列と for 文を使わない場合の書き方

    p = 1

    For i = LB_data1_1D To UB_data1_1D
      arrstring = data1(i, 2)

      ' Split・LBound・UBound 関数格納用変数へ代入(メモリリーク対策)
      Split_arrstring_vbLf = Split(arrstring, vbLf)
      LB_Split_arrstring_vbLf = LBound(Split_arrstring_vbLf)
      UB_Split_arrstring_vbLf = UBound(Split_arrstring_vbLf)

      If UB_Split_arrstring_vbLf = 0 Or UB_Split_arrstring_vbLf = -1 Then
        For k = LB_data1_2D To UB_data1_2D
          data2(p, k) = data1(i, k)
        Next k
'        data2(p, 1) = data1(i, 1)
'        data2(p, 2) = data1(i, 2)
'        data2(p, 3) = data1(i, 3)

        p = p + 1
      End If

      If UB_Split_arrstring_vbLf > 0 Then
        For m = LB_Split_arrstring_vbLf + 1 To UB_Split_arrstring_vbLf + 1
          If m = LB_Split_arrstring_vbLf + 1 Then
            num(0) = InStr(m, data1(i, 2), vbLf) ' 配列 data1 の i 行 2列目(都道府県列)データを、Instr 関数で m(= 1)文字目から区切り文字(vbLf)がある最初の位置の値を動的配列 num(0) に格納
            num(1) = InStr(m, data1(i, 3), vbLf) ' 配列 data1 の i 行 3列目(県庁所在地列)データを、Instr 関数で m(= 1)文字目から区切り文字(vbLf)がある最初の位置の値を動的配列 num(1) に格納

            data2(p, 1) = data1(i, 1)
            data2(p, 2) = Left(data1(i, 2), num(0) - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Left 関数で、最初の区切り文字位置のひとつ前(num(0) - 1)までの文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Left(data1(i, 3), num(1) - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Left 関数で、最初の区切り文字位置のひとつ前(num(1) - 1)までの文字列を取得、配列 data2 の p 行 3列目に格納

'            data2(p, 2) = Mid(data1(i, 2), m, num(0) - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、変数 m 文字目から最初の区切り文字位置のひとつ前(num(0) - 1)までの文字列を取得、配列 data2 の p 行 2列目に格納
'            data2(p, 3) = Mid(data1(i, 3), m, num(1) - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、変数 m 文字目から最初の区切り文字位置のひとつ前(num(1) - 1)までの文字列を取得、配列 data2 の p 行 3列目に格納

            p = p + 1
          End If

          If m <> LB_Split_arrstring_vbLf + 1 And m <> UB_Split_arrstring_vbLf + 1 Then
            num(2) = InStr(num(0) + 1, data1(i, 2), vbLf) ' 配列 data1 の i 行 2列目(都道府県列)データを Instr 関数で、動的配列 num(0) に格納されている区切り文字位置の次の位置(num(0) + 1)から次の区切り文字(vbLf)がある位置の値を動的配列 num(2) に格納
            num(3) = InStr(num(1) + 1, data1(i, 3), vbLf) ' 配列 data1 の i 行 2列目(県庁所在地)データを Instr 関数で、動的配列 num(1) に格納されている区切り文字位置の次の位置(num(1) + 1)から次の区切り文字(vbLf)がある位置の値を動的配列 num(3) に格納
            
            data2(p, 1) = data1(i, 1)
            data2(p, 2) = Mid(data1(i, 2), num(0) + 1, num(2) - num(0) - 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、動的配列 num(0) に格納されている区切り文字位置の次の位置(num(0) + 1)から次の区切り文字位置のひとつ前までの文字数(num(2) - num(0) - 1)を指定して文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Mid(data1(i, 3), num(1) + 1, num(3) - num(1) - 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、動的配列 num(1) に格納されている区切り文字位置の次の位置(num(1) + 1)から次の区切り文字位置のひとつ前までの文字数(num(3) - num(1) - 1)を指定して文字列を取得、配列 data2 の p 行 3列目に格納

            num(0) = num(2) ' 配列 data1 の i 行 2列目(都道府県)の区切り文字開始位置の値(num(0))を、次の区切り文字位置の値(num(2))に更新(複数の区切り文字がある場合の繰り返し処理対応)
            num(1) = num(3) ' 配列 data1 の i 行 3列目(県庁所在地)の区切り文字開始位置の値(num(1))を、次の区切り文字位置の値(num(3))に更新(複数の区切り文字がある場合の繰り返し処理対応)

            p = p + 1
          End If

          If m = UB_Split_arrstring_vbLf + 1 Then
            data2(p, 1) = data1(i, 1)
            data2(p, 2) = Mid(data1(i, 2), num(0) + 1) ' 配列 data1 の i 行 2列目(都道府県)のデータを Mid 関数で、動的配列 num(0) に格納されている最後の区切り文字位置の次の位置(num(0) + 1)からデータ終端まで文字列を取得、配列 data2 の p 行 2列目に格納
            data2(p, 3) = Mid(data1(i, 3), num(1) + 1) ' 配列 data1 の i 行 3列目(県庁所在地)のデータを Mid 関数で、動的配列 num(1) に格納されている最後の区切り文字位置の次の位置(num(1) + 1)からデータ終端まで文字列を取得、配列 data2 の p 行 3列目に格納

            p = p + 1
          End If
        Next m

        ' カウンタ用変数 i をインクリメントして配列 data1(i, 1)の次の地方区分行に進む前に、区切り文字位置の値格納用動的配列すべての要素を for 文を使って 0 で初期化
        For k = LB_num To UB_num ' 動的配列の最大要素までループ処理
          num(k) = 0 ' 動的配列 num の i 番目に 0 を設定
        Next k
'        num(0) = 0 ' for 文を使わない場合の書き方
'        num(1) = 0 ' for 文を使わない場合の書き方
'        num(2) = 0 ' for 文を使わない場合の書き方
'        num(3) = 0 ' for 文を使わない場合の書き方

      End If

    Next i

  Case 3 ' Case 2 と同じ処理内容、変更点は各配列の行・列・要素番号への直接値の指定からカウンタ用変数 k と For 文を使ってループ処理に変更

    ReDim num(3)

    ' LBound・UBound 関数格納用変数へ代入(メモリリーク対策)
    LB_num = LBound(num)
    UB_num = UBound(num)

    For i = LB_num To UB_num
      num(i) = 0
    Next i
'    num = Array(0, 0, 0, 0)

    p = 1

    For i = LB_data1_1D To UB_data1_1D
      arrstring = data1(i, 2)

      ' Split・LBound・UBound 関数格納用変数へ代入(メモリリーク対策)
      Split_arrstring_vbLf = Split(arrstring, vbLf)
      LB_Split_arrstring_vbLf = LBound(Split_arrstring_vbLf)
      UB_Split_arrstring_vbLf = UBound(Split_arrstring_vbLf)

      If UB_Split_arrstring_vbLf = 0 Or UB_Split_arrstring_vbLf = -1 Then
        For k = LB_data1_2D To UB_data1_2D
          data2(p, k) = data1(i, k)
        Next k
'        data2(p, 1) = data1(i, 1)
'        data2(p, 2) = data1(i, 2)
'        data2(p, 3) = data1(i, 3)

        p = p + 1
      End If

      If UB_Split_arrstring_vbLf > 0 Then
        For m = LB_Split_arrstring_vbLf + 1 To UB_Split_arrstring_vbLf + 1
          If m = LB_Split_arrstring_vbLf + 1 Then
            data2(p, 1) = data1(i, 1)

            For k = LB_data1_2D + 1 To UB_data1_2D ' 2列目から 2次元最大要素までループ処理
              num(k - 2) = InStr(m, data1(i, k), vbLf) ' 配列 data1 の i 行 k 列目(都道府県列・県庁所在地)データを、Instr 関数で m(= 1)文字目から区切り文字(vbLf)がある最初の位置の値を動的配列 num(k - 2) に格納
              data2(p, k) = Left(data1(i, k), num(k - 2) - 1) ' 配列 data1 の i 行 k 列目(都道府県・県庁所在地)のデータを Left 関数で、最初の区切り文字位置のひとつ前(num(k - 2) - 1)までの文字列を取得、配列 data2 の p 行 k 列目に格納
'              data2(p, k) = Mid(data1(i, k), m, num(k - 2) - 1) ' 配列 data1 の i 行 k 列目(都道府県・県庁所在地)のデータを Mid 関数で、変数 m 文字目から最初の区切り文字位置のひとつ前(num(k - 2) - 1)までの文字列を取得、配列 data2 の p 行 k 列目に格納
            Next k
'            num(0) = InStr(m, data1(i, 2), vbLf)
'            num(1) = InStr(m, data1(i, 3), vbLf)

'            data2(p, 2) = Left(data1(i, 2), num(0) - 1)
'            data2(p, 3) = Left(data1(i, 3), num(1) - 1)
'            data2(p, 2) = Mid(data1(i, 2), m, num(0) - 1)
'            data2(p, 3) = Mid(data1(i, 3), m, num(1) - 1)

            p = p + 1
          End If

          If m <> LB_Split_arrstring_vbLf + 1 And m <> UB_Split_arrstring_vbLf + 1 Then
            data2(p, 1) = data1(i, 1)

            For k = LB_data1_2D + 1 To UB_data1_2D ' 2列目から 2次元最大要素までループ処理
              num(k) = InStr(num(k - 2) + 1, data1(i, k), vbLf) ' 配列 data1 の i 行 k 列目(都道府県列・県庁所在地)データを Instr 関数で、動的配列 num(k - 2) に格納されている区切り文字位置の次の位置(num(k - 2) + 1)から次の区切り文字(vbLf)がある位置の値を動的配列 num(k) に格納
              data2(p, k) = Mid(data1(i, k), num(k - 2) + 1, num(k) - num(k - 2) - 1) ' 配列 data1 の i 行 k 列目(都道府県・県庁所在地)のデータを Mid 関数で、動的配列 num(k - 2) に格納されている区切り文字位置の次の位置(num(k - 2) + 1)から次の区切り文字位置のひとつ前までの文字数(num(k) - num(k - 2) - 1)を指定して文字列を取得、配列 data2 の p 行 k 列目に格納
              num(k - 2) = num(k) ' 配列 data1 の i 行 k 列目(都道府県・県庁所在地)の区切り文字開始位置の値(num(k))を、次の区切り文字位置の値(num(k - 2))に更新(複数の区切り文字がある場合の繰り返し処理対応)
            Next k
'            num(2) = InStr(num(0) + 1, data1(i, 2), vbLf)
'            num(3) = InStr(num(1) + 1, data1(i, 3), vbLf)

'            data2(p, 2) = Mid(data1(i, 2), num(0) + 1, num(2) - num(0) - 1)
'            data2(p, 3) = Mid(data1(i, 3), num(1) + 1, num(3) - num(1) - 1)

'            num(0) = num(2)
'            num(1) = num(3)

            p = p + 1
          End If

          If m = UB_Split_arrstring_vbLf + 1 Then
            data2(p, 1) = data1(i, 1)

            For k = LB_data1_2D + 1 To UB_data1_2D ' 2列目から 2次元最大要素までループ処理
              data2(p, k) = Mid(data1(i, k), num(k - 2) + 1) ' 配列 data1 の i 行 k 列目(都道府県・県庁所在地)のデータを Mid 関数で、動的配列 num(k - 2) に格納されている最後の区切り文字位置の次の位置(num(k - 2) + 1)からデータ終端まで文字列を取得、配列 data2 の p 行 k 列目に格納
            Next k
'            data2(p, 2) = Mid(data1(i, 2), num(0) + 1)
'            data2(p, 3) = Mid(data1(i, 3), num(1) + 1)

            p = p + 1
          End If
        Next m

        For k = LB_num To UB_num
          num(k) = 0
        Next k
'        num(0) = 0
'        num(1) = 0
'        num(2) = 0
'        num(3) = 0

      End If

    Next i

  Case 4 ' Split 関数で配列に格納した各要素を、インクリメントしたカウンタ変数 s を使って 2次元配列 data2 の行番号を指定して各要素を格納

    Dim tmp As Variant ' Split 関数で返した配列の格納用変数
    Dim s As Long ' 2次元配列 data2 の行番号変数 p 用インクリメント変数

    p = 1
    s = 0 ' 0 で初期化

    ' LBound・UBound 関数格納用変数(メモリリーク対策)
    Dim LB_tmp As Variant ' LB_tmp = LBound(tmp)
    Dim UB_tmp As Variant ' UB_tmp = UBound(tmp)

    For i = LB_data1_1D To UB_data1_1D
      arrstring = data1(i, 2)

      ' Split・UBound 関数格納用変数へ代入(メモリリーク対策)
      Split_arrstring_vbLf = Split(arrstring, vbLf)
      UB_Split_arrstring_vbLf = UBound(Split_arrstring_vbLf)

      If UB_Split_arrstring_vbLf = 0 Or UB_Split_arrstring_vbLf = -1 Then
        For k = LB_data1_2D To UB_data1_2D
          data2(p, k) = data1(i, k)
        Next k
'        data2(p, 1) = data1(i, 1)
'        data2(p, 2) = data1(i, 2)
'        data2(p, 3) = data1(i, 3)

        p = p + 1
      End If

      If UB_Split_arrstring_vbLf > 0 Then

        For k = LB_data1_2D + 1 To UB_data1_2D
          ' Split 関数の第 1引数に区切り文字列がある 2次元配列を、第 2引数に区切り文字(vbLf)を指定
          ' 1次元配列として返した区切られた各文字列をバリアント型変数 tmp に格納
          tmp = Split(data1(i, k), vbLf)

        ' LBound・UBound 関数格納用変数へ代入(メモリリーク対策)
        LB_tmp = LBound(tmp)
        UB_tmp = UBound(tmp)

          ' 分割した都道府県・県庁所在地別の地方区分名を 2次元配列 data2 に格納
          If k = 2 Then ' For 文内で都道府県・県庁所在地別に行分割処理を行う際に地方区分名の代入は 1度だけでいいため、カウンタ変数 k の初期値 2(都道府県列)の時だけ地方区分名を代入処理
            For m = LB_tmp To UB_tmp ' 1次元配列 tmp の最大要素までループ処理
              data2(p + s, 1) = data1(i, 1) ' 2次元配列 data1 の地方区文名を 2次元配列 data2 に代入、2次元配列 data2 の行番号 p をインクリメントした変数 s を使って行番号指定(ループ開始処理時の変数 s の初期値は 0、ループ処理を抜けたら 0 で初期化)
              s = s + 1 ' 変数 s をインクリメントして次の行番号 p に加算
            Next m

            s = 0 ' 変数 s を 0 で初期化

          End If

          ' 分割した都道府県・県庁所在地名を 2次元配列 data2 に格納
          For m = LB_tmp To UB_tmp ' 1次元配列 tmp の最大要素までループ処理
            data2(p + s, k) = tmp(m) ' 1次元配列 tmp の都道府県名・県庁所在地名を 2次元配列 data2 に代入、2次元配列 data2 の行番号 p をインクリメントした変数 s を使って行番号指定(ループ開始処理時の変数 s の初期値は 0、ループ処理を抜けたら 0 で初期化)
            s = s + 1 ' 変数 s をインクリメントして次の行番号 p に加算
          Next m

          s = 0 ' 変数 s を 0 で初期化

        Next k

        p = p + UB_tmp + 1 ' 配列 data2 の行番号 p に、1次元配列 tmp の最大要素(UBound 関数使用)と 1 を足して次の配列 data2 への代入先行番号を更新(1次元配列 tmp の開始要素番号が 0 からのため + 1 で調整)

      End If

    Next i

  Case Else ' エラー処理(Sub プロシージャー終了)

    MsgBox "変数 val3 に指定された値(1~3)以外の " & val3 & " が代入されているため処理を終了します"
    Exit Sub

  End Select

' ----------

  ' 二次元配列 data2 の内容を、貼り付け先シートの Range で指定したセルから Resize で範囲を変更してセルに代入
  ws2.Range("A2").Resize(UB_data2_1D, UB_data2_2D).Value = data2
  ws2.Activate

  ' テスト用シートに出力する場合は以下のテスト用シートを格納したオブジェクト変数に変更
'  ws3.Range("A2").Resize(UB_data2_1D, UB_data2_2D).Value = data2
'  ws3.Activate

' ----------

  ' 実行速度計測結果表示
  Debug.Print Format(Timer - starttime, "0.00秒")
  
End Sub