今回は、プログラムを知らないユーザーに除外したい列を指定してもらう方法です。
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になってしまう場合の処理をどうするかを決めておくとよいでしょう(空行は書き込まないなど)。
コメント