今回は、プログラムを知らないユーザーに除外したい列を指定してもらう方法です。
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
実行イメージ
- ユーザーが「Sheet1」のA1セルに「1,3,5」などと入力する(※Excelの列番号感覚)
- マクロ
ImportCSV_ExcludeColumns_FromSheetCell
を実行 - CSVを1行ずつ読み込み、
Split
→ 配列spl
→ 除外列リストにあるインデックスをスキップ - 結果、「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
補足・応用ポイント
- ユーザーが入力する列番号の定義
- 「CSVの1列目を除外したいのか?」→ ユーザーが 「1」 と入力 → 内部で
-1
して実際のインデックス0
にする - もしユーザーが0-basedで入力してくれるなら、
ConvertCommaStringToArray(..., False)
のようにして、変換時に-1
しないようにすればOKです。
- 「CSVの1列目を除外したいのか?」→ ユーザーが 「1」 と入力 → 内部で
- ヘッダ行をスキップしたい場合
- 先頭行だけ
Line Input #fileNo, textLine
で読み込んで何もしない、または別の場所に書き込む等の処理を加えれば対応できます。
- 先頭行だけ
- 書き込み先シートを分けたい場合
ThisWorkbook.Worksheets("Sheet2").Cells(...)
のように、書き込み先を別シートに指定も可能です。
- 途中の列が全部除外で空になってしまうと困るようなケース
- データがすべて飛ばされて列0になってしまう場合の処理をどうするかを決めておくとよいでしょう(空行は書き込まないなど)。
コメント