LF(改行)でセルの内容を分割する:Excel VBA

以下に示すように,Excelの1つのセルに複数行のデータが書き込まれている際に,改行で区切って各々別のセルとなるように分割するマクロ(VBA)です。

このコードではこちらの「ステータスバーの更新頻度を下げて処理速度を向上させる:Excel VBA」を使用しています。

実行例
' 参照設定 mscorlib
' LF(改行)でセルの内容を分割する
' src: コピー元のRange
' dst: コピー先のRange(先頭セルのみで良い)
' add_row_number: 当初の行番号が分かるように,先頭列へコピー元の行番号を付加します。
' skip: 改行分割処理をスキップする(つまり単純コピーになる)列番号を昇順でVariant型の配列で渡す
Sub SplitLF(src As Range, dst As Range, _
    Optional add_row_number As Boolean = True, _
    Optional skip As Variant)
    Dim i As Long
    Dim j As Long
    Dim k As Long
    Dim n_col As Long
    Dim n_row As Long
    n_col = src.Columns.Count
    n_row = src.Rows.Count
 
    ' スキップ配列処理初期化
    Dim skip_count As Long
    Dim skip_array_it As Long ' イテレータ
    If IsMissing(skip) Then
        skip_count = -1
        skip_array_it = 999
    Else
        skip_count = UBound(skip)
        skip_array_it = LBound(skip)
        If add_row_number Then
            For i = LBound(skip) To UBound(skip)
                skip(i) = skip(i) + 1
            Next
        End If
    End If
 
    Dim a As New ArrayList
 
    ' 行番号追記処理初期化
    If add_row_number Then
        n_col = n_col + 1
    End If
 
    ' セルの内容をArrayListへコピー
    Dim data As Variant
    data = src.Value
    For i = LBound(data, 1) To UBound(data, 1)
        Dim b() As String
        ReDim b(1 To n_col)
        If add_row_number Then
            b(1) = src.Row + i - 1 ' 行番号代入
            For j = 1 To n_col - 1
                b(j + 1) = data(i, j)
            Next
        Else
            For j = 1 To n_col
                b(j) = data(i, j)
            Next
        End If
        a.Add b
    Next
    ' ArrayList上で改行分割処理
    For j = 1 To n_col
        If skip_array_it <= skip_count Then
            If skip(skip_array_it) = j Then
                skip_array_it = skip_array_it + 1
                StatusBarUpdate "列" & j & "/" & n_col & "-> skip"
            Else
                i = 0
                Do While i < a.Count
                    StatusBarUpdate "列" & j & "/" & n_col & "->" & i & "/" & a.Count
                    ' a1 へ 1行格納
                    Dim a1 As Variant
                    a1 = a.Item(i)
                    If Len(a.Item(i)(j)) > 0 Then
                        ' j列目の文字を改行区切りでSplit
                        Dim str() As String
                        str = Split(a1(j), vbLf)
                        If UBound(str) > LBound(str) Then
                            Dim a2 As Variant
                            ' 増える要素分だけArrayList.Insert
                            For k = 1 To UBound(str) - LBound(str)
                                a2 = a1
                                a2(j) = str(k)
                                a.Insert i + k, a2 ' i+k番目にa1のj列目を改行区切りで分割した配列のk番目に置換した配列データを挿入
                            Next
                            ' 元の要素の置換
                            a2 = a1
                            a2(j) = str(0)
                            a.Item(i) = a2
                        End If
                        ' 増やした要素数+1行進める
                        i = i + UBound(str) - LBound(str) + 1
                    Else
                        i = i + 1
                    End If
                Loop
            End If
        End If
    Next
    Application.StatusBar = False
    ' 書き込み先へ入力
    For i = 0 To a.Count - 1
        dst.Cells(i + 1, 1).Resize(, n_col) = a.Item(i)
    Next
End Sub

使用例

Sub TEST()
    Dim src_ws As Worksheet
    Dim src_range As Range
    Set src_ws = Sheets("Sheet1")
    src_ws.Activate
    With src_ws.Range("A2").CurrentRegion
        Set src_range = src_ws.Range(src_ws.Range("A3"), .Cells(.Rows.Count - 2, 18))
    End With
    Dim ws As Worksheet
    Set ws = Sheets.Add(After:=src_ws)
    Call SplitLF(src_range, ws.Range("A3"), skip:=Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18))
End Sub
カテゴリー: PROG

0件のコメント

コメントする

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください