PR

【Excel vb】CSVの不要な列を除いてExcelに取り込む方法「ユーザーに取込列を指定してもらう」

スポンサーリンク
この記事は約11分で読めます。

今回は、プログラムを知らないユーザーに除外したい列を指定してもらう方法です。

1. シート上のセルから除外列リストを読み込む例

以下のサンプルでは、「Sheet1」のA1セルにユーザーが除外したい列番号をカンマ区切り(例:1,3,5)で入力するとして、それをマクロ内で読み込んで配列に変換し、CSV取り込みの際に該当列を出力から除外するイメージです。

  • ユーザーには「CSVの1列目を除外したい場合は1と入力してね」とガイドします。
  • ただし、VBA内で実際に配列として扱う際には、CSVの配列は0-basedになるので、ユーザーが入力した値(1)はインデックス(0)として扱うといった調整が必要です。

サンプルコード

Sub ImportCSV_ExcludeColumns_FromSheetCell()
    '=== [1] 前提設定 =========================
    Dim csvFilePath As String
    csvFilePath = "C:\temp\testdata.csv"  ' CSVファイルパスを設定
    
    Dim delimiter As String
    delimiter = ","                       ' CSV区切り文字
    
    ' 「Sheet1」のA1にユーザーが除外したい列番号を,区切りで入力している想定
    '  例: A1セル = "1,3,5"
    Dim excludeColumnsString As String
    excludeColumnsString = ThisWorkbook.Worksheets("Sheet1").Range("A1").Value
    
    ' シートに入力されている除外列番号を配列にする
    ' CSVは0-basedで列を扱うため、ユーザーが入力したもの(1)→実際はインデックス0
    Dim excludeColumns() As Long
    excludeColumns = ConvertCommaStringToArray(excludeColumnsString, True)
    ' 第二引数 True にしているのは
    '  「ユーザーが1-basedで入力した番号を0-basedへ変換する」ためのフラグ
    
    ' データを書き込む開始セル位置(適宜変更)
    Dim startRow As Long: startRow = 1
    Dim startCol As Long: startCol = 1
    
    '=== [2] CSV読み込み =========================
    Dim fileNo As Integer
    Dim textLine As String
    Dim spl() As String
    Dim currentRow As Long: currentRow = startRow
    Dim colIndex As Long
    
    fileNo = FreeFile
    Open csvFilePath For Input As #fileNo
    
    Do Until EOF(fileNo)
        Line Input #fileNo, textLine
        spl = Split(textLine, delimiter)
        
        '=== [3] 除外列を判定しつつ書き込み =============
        Dim writeCol As Long
        writeCol = startCol
        
        For colIndex = LBound(spl) To UBound(spl)
            ' 除外リストに含まれているか判定
            If Not IsInArray(colIndex, excludeColumns) Then
                ' 除外リストに無ければ、セルへ出力
                ThisWorkbook.Worksheets("Sheet1").Cells(currentRow, writeCol).Value = spl(colIndex)
                writeCol = writeCol + 1
            End If
        Next colIndex
        
        currentRow = currentRow + 1
    Loop
    
    Close #fileNo
    
    MsgBox "CSVの取込が完了しました(不要列を除外済み)。"
End Sub

'=== [補助関数1] カンマ区切り文字列を Long配列に変換する ===
' str = "1,3,5" → Array(1,3,5) のような Long型配列を返す
' isUser1Based = True の場合は、ユーザーが1-basedで指定しているので返却値は全て -1 する。
Private Function ConvertCommaStringToArray(str As String, isUser1Based As Boolean) As Long()
    Dim tmp As Variant
    tmp = Split(str, ",")  ' カンマ区切りで分割
    
    Dim result() As Long
    ReDim result(LBound(tmp) To UBound(tmp))
    
    Dim i As Long
    For i = LBound(tmp) To UBound(tmp)
        If isUser1Based Then
            result(i) = CLng(tmp(i)) - 1
        Else
            result(i) = CLng(tmp(i))
        End If
    Next i
    
    ConvertCommaStringToArray = result
End Function

'=== [補助関数2] 指定した値が配列内に含まれているか判定する ===
Private Function IsInArray(ByVal val As Long, ByVal arr() As Long) As Boolean
    Dim i As Long
    For i = LBound(arr) To UBound(arr)
        If arr(i) = val Then
            IsInArray = True
            Exit Function
        End If
    Next i
    IsInArray = False
End Function

実行イメージ

  1. ユーザーが「Sheet1」のA1セルに「1,3,5」などと入力する(※Excelの列番号感覚)
  2. マクロ ImportCSV_ExcludeColumns_FromSheetCell を実行
  3. CSVを1行ずつ読み込み、Split → 配列 spl → 除外列リストにあるインデックスをスキップ
  4. 結果、「A1セル」に指定された列番号(1,3,5)に相当するCSV列は飛ばしてシートに貼り付ける

2. InputBox で「除外列番号」をユーザーに入力してもらう例

マクロ実行時にポップアップで「除外したい列番号」を入力してもらう方法も可能です。たとえば下記のようにすると、実行時に入力ボックスが出現し、ユーザーがカンマ区切りで列番号を入力できるようになります。

サンプルコード

Sub ImportCSV_ExcludeColumns_InputBox()
    Dim csvFilePath As String
    csvFilePath = "C:\temp\testdata.csv"
    
    Dim delimiter As String
    delimiter = ","
    
    '=== [ユーザーに除外する列番号を入力させる] ===
    Dim userInput As String
    userInput = InputBox("除外したい列番号をカンマ区切りで入力してください。" & vbCrLf & _
                         "例: 1,3,5 (CSVの1列目・3列目・5列目を除外)")
                         
    If userInput = "" Then
        MsgBox "入力がキャンセルされました。処理を中止します。"
        Exit Sub
    End If
    
    ' ユーザー入力の値を配列に変換(1-based想定 → 実際は-1して0-based化)
    Dim excludeColumns() As Long
    excludeColumns = ConvertCommaStringToArray(userInput, True)
    
    Dim startRow As Long: startRow = 1
    Dim startCol As Long: startCol = 1
    
    Dim fileNo As Integer
    Dim textLine As String
    Dim spl() As String
    Dim currentRow As Long: currentRow = startRow
    Dim colIndex As Long
    
    fileNo = FreeFile
    Open csvFilePath For Input As #fileNo
    
    Do Until EOF(fileNo)
        Line Input #fileNo, textLine
        spl = Split(textLine, delimiter)
        
        Dim writeCol As Long
        writeCol = startCol
        
        For colIndex = LBound(spl) To UBound(spl)
            If Not IsInArray(colIndex, excludeColumns) Then
                Cells(currentRow, writeCol).Value = spl(colIndex)
                writeCol = writeCol + 1
            End If
        Next colIndex
        
        currentRow = currentRow + 1
    Loop
    
    Close #fileNo
    
    MsgBox "除外列を指定してCSVを取り込みました。"
End Sub

' --- 補助関数は上記(1)と同じ ---
Private Function ConvertCommaStringToArray(str As String, isUser1Based As Boolean) As Long()
    Dim tmp As Variant
    tmp = Split(str, ",")
    
    Dim result() As Long
    ReDim result(LBound(tmp) To UBound(tmp))
    
    Dim i As Long
    For i = LBound(tmp) To UBound(tmp)
        If isUser1Based Then
            result(i) = CLng(tmp(i)) - 1
        Else
            result(i) = CLng(tmp(i))
        End If
    Next i
    
    ConvertCommaStringToArray = result
End Function

Private Function IsInArray(ByVal val As Long, ByVal arr() As Long) As Boolean
    Dim i As Long
    For i = LBound(arr) To UBound(arr)
        If arr(i) = val Then
            IsInArray = True
            Exit Function
        End If
    Next i
    IsInArray = False
End Function

補足・応用ポイント

  1. ユーザーが入力する列番号の定義
    • 「CSVの1列目を除外したいのか?」→ ユーザーが 「1」 と入力 → 内部で -1 して実際のインデックス 0 にする
    • もしユーザーが0-basedで入力してくれるなら、ConvertCommaStringToArray(..., False) のようにして、変換時に-1しないようにすればOKです。
  2. ヘッダ行をスキップしたい場合
    • 先頭行だけ Line Input #fileNo, textLine で読み込んで何もしない、または別の場所に書き込む等の処理を加えれば対応できます。
  3. 書き込み先シートを分けたい場合
    • ThisWorkbook.Worksheets("Sheet2").Cells(...) のように、書き込み先を別シートに指定も可能です。
  4. 途中の列が全部除外で空になってしまうと困るようなケース
    • データがすべて飛ばされて列0になってしまう場合の処理をどうするかを決めておくとよいでしょう(空行は書き込まないなど)。

にほんブログ村 IT技術ブログ IT技術メモへ

コメント

タイトルとURLをコピーしました