エクセルVBAで値にカンマを含むCSVを変数に入れたい話

VBA

CSVとはカンマ・セパレート・バリューの名の通り値と値をカンマ( , ) で区切る約束のファイル形式ですが、業務をしていると値のなかにカンマが入っていることもあると思います。

そういうファイルはCSVとしての体裁を保つために値をダブルクォーテーションで囲っており、ダブルクォーテーションが閉じた次のカンマを区切り文字として使っています。

こういう形式のCSVでも、業務でCSVやエクセルを使っていると業務効率化のためスクリプトを組もうというのが自然の摂理ですよね。
ですが、値の中にカンマが入っていると困ってしまうのです。

というのも、VBAでは値をゴニョニョするときは変数に入れた方が早いという原則(思い込み)がありますから、カンマでsplitして要素を配列に入れていこうとする訳です。
そういうわけで、上述のようなファイルだと想定外の結果になってしまうわけですね。

そこで、ダブルクォーテーションとカンマの組み合わせに着目したCSV読み込みスクリプトを考えることにしたのです。

スポンサーリンク

コード

Public Sub output_csv(CSV_path As String, sheet_name As String, dest_sheet As Worksheet)
	' CSVヘッダー検査とCSVの中身が入った変数の用意し書き込み
	' 引数:CSVのパス、 シート名、書き込み先シート
	' 戻り値:CSVの内容が入った変数
	
	Dim c As Long
	Dim str_line As String
	Dim arr_line() As String
	Dim quot_line As String
	Dim quot_cnt As Long
	Dim quot_match As String
	Dim index_cnt As Long
	Dim result As Boolean
	
	' csvファイルをオープン
	Open CSV_path For Input As #1
	' 文中のカンマに対応するためダブルクォーテーションで判定する
	c = 1
	Do Until EOF(1)
		Line Input #1, str_line
		index_cnt = 0
		quot_line = ""
		' ダブルクオーテーションの中のカンマを無視してquot_lineにいれる
		quot_cnt = 0
		Dim q As Long
		For q = 1 To Len(str_line)
			quot_match = Mid$(str_line, q, 1)   ' Mid$でstring型で返せる
			
			' ダブルクォーテーションの時カウントアップ
			If quot_match = """" Then ' "は""で囲んで"でエスケープする
				quot_cnt = quot_cnt + 1
				
			' ダブルクォーテーションカウントが奇数なら文字結合
			ElseIf quot_cnt Mod 2 = 1 Then
				quot_line = quot_line & quot_match
				
			' 偶数ならquot_lineをarr_lineにいれてから初期化
			Else
				ReDim Preserve arr_line(index_cnt)
				arr_line(index_cnt) = quot_line
				index_cnt = index_cnt + 1
				quot_line = ""
			End If
		Next q
		' 最後の列を格納
		ReDim Preserve arr_line(index_cnt)  ' 要素数を追加
		arr_line(index_cnt) = quot_line ' 1レコードを配列に追加
		
		' ヘッダーチェックしてFalseだったら終了
		If c = 1 Then
			result = check_headers(sheet_name, arr_line) 'ヘッダーチェック用の別関数
			If result = False Then
				to_end
				End
			End If
		End If
		
		' 書き込み
		Dim i As Long
		For i = 0 To UBound(arr_line)
			dest_sheet.Cells(c, i + 1).Value = arr_line(i)
		Next i
		c = c + 1
	Loop
	Close #1
	
End Sub

CSVファイルの例としては

"属性1","属性2","属性3"
"2020/11/04","営業部","1,000円"

みたいなやつです。
“1,000円”なんてふうに来られちゃうとちょっと疲れますね。

紹介しといてなんですが、上記コード遅い気がしています。
ファイルを1行ずつチェックしてカウントして配列増やしたり値を分けたりなのでこんなもんかとも思いますが、もっと早い処理あるんでしょうか?

ところで、私は非IT系の企業で社内SEしているわけですが意外と皆さんCSVというものが何なのかは知っているんですよね。
私は新卒でSIer企業に入ってシステムに触れるようになって初めて知ったんですがうちの社員がどこでCSVに触れているのか謎・・・

コメント

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