エクセルでCSVファイルの保存時に値をダブルクオートで囲いたい

法人向けのオンライン講座でのサポート案件から。

CSVファイルをエクセルで開いて別ディレクトリに置き換える仕事がある。
ここで、ファイルの保存時に、元あったデータの前後のダブルクオートが消えてしまう。
クライアント企業のシステムの仕様の関係で、データの前後のダブルクオートが消えないようにしたい。

とのこと。

たとえば、こんなCSVファイルがマクロの入ったエクセルファイルと同じフォルダにあるとする。

data.csv

"ID","会社名","都道府県","電話番号","資本金","問い合わせ回数"
"1","株式会社アイウエオ","東京都","03-1234-5678","50000000","20"
"2","株式会社カキクケコ","大阪府","06-2345-6789","100000000","35"
"3","株式会社サシスセソ","愛知県","052-3456-7890","75000000","40"
"4","株式会社タチツテト","福岡県","092-4567-8901","80000000","15"
"5","株式会社ナニヌネノ","北海道","011-5678-9012","60000000","25"
"6","株式会社ハヒフヘホ","広島県","082-6789-0123","30000000","30"
"7","株式会社マミムメモ","京都府","075-7890-1234","70000000","45"
"8","株式会社ヤユヨ","宮城県","022-8901-2345","90000000","50"
"9","株式会社ラリルレロ","沖縄県","098-9012-3456","55000000","10"
"10","株式会社ワヲン","群馬県","027-0123-4567","65000000","55"

CSVファイルをエクセルで開くこと自体は簡単。
通常のエクセルファイルと同様、以下で開くことができる。
Sub open_and_save_csv_ng()
    'csv ファイルを通常のエクセルファイルのように開く
    'セルの中身を行ごとに順に読んでいき、テキストファイルとして保存する
    '保存時の拡張子は .csv とする

'csvファイルを開き、ファイル内で使われているセル範囲を取得する
Dim wb As Workbook
Dim ws As Worksheet

Set wb = Workbooks.Open(Filename:=ThisWorkbook.Path & "\data.csv")
Set ws = wb.Worksheets(1)

wb.SaveAs Filename:=ThisWorkbook.Path & "\output_ng.csv"
wb.Close

Set ws = Nothing
Set wb = Nothing

End Sub


問題は、後半の saveAs メソッド。
これを実行すると、以下のようなダブルクオートが落ちたデータになってしまう。
(save メソッドでも結果は同じ)

output_ng.csv

ID,会社名,都道府県,電話番号,資本金,問い合わせ回数
1,株式会社アイウエオ,東京都,03-1234-5678,50000000,20
2,株式会社カキクケコ,大阪府,06-2345-6789,100000000,35
3,株式会社サシスセソ,愛知県,052-3456-7890,75000000,40
4,株式会社タチツテト,福岡県,092-4567-8901,80000000,15
5,株式会社ナニヌネノ,北海道,011-5678-9012,60000000,25
6,株式会社ハヒフヘホ,広島県,082-6789-0123,30000000,30
7,株式会社マミムメモ,京都府,075-7890-1234,70000000,45
8,株式会社ヤユヨ,宮城県,022-8901-2345,90000000,50
9,株式会社ラリルレロ,沖縄県,098-9012-3456,55000000,10
10,株式会社ワヲン,群馬県,027-0123-4567,65000000,55

「開いて保存しただけだろ」と言いたくなるところだが。
こういう余計な加工をしていただけるところがいかにもエクセルらしい。

エクセルVBAを使うという前提でこの問題の回避策を考えるなら、テキストファイルとしてアウトプットファイルを作るしかなさそうだ。
ということで、以下はそんなサンプルコード。

Sub open_and_save_csv_ok()
    'csv ファイルを通常のエクセルファイルのように開く
    'セルの中身を行ごとに順に読んでいき、テキストファイルとして保存する
    '保存時の拡張子は .csv とする

'csvファイルを開き、ファイル内で使われているセル範囲を取得する
Dim wb As Workbook
Dim ws As Worksheet
Dim rgAll As Range

Set wb = Workbooks.Open(Filename:=ThisWorkbook.Path & "\data.csv")
Set ws = wb.Worksheets(1)
Set rgAll = ws.UsedRange

'セル範囲の行数、列数を取得する
Dim col_size As Long
Dim row_size As Long
row_size = rgAll.Rows.Count
col_size = rgAll.Columns.Count

Dim fso As Object
Dim ts As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.CreateTextFile(ThisWorkbook.Path & "\output_ok.csv", True)

Dim cell_value As String ' セルの値
Dim row_text As String 'アウトプットファイルに書き込むため値を行ごとに生成してこの変数に格納する

'セル範囲に対して、行ごとに処理
Dim i As Long, j As Long
For i = 0 To row_size - 1
    row_text = "" '初期化
    For j = 0 To col_size - 1 '調査対象の行内での列ごとに
        '以下は不要ではあるが、何をやっているか分かりやすくなるので出力
        Debug.Print Range("A1").Offset(i, j).Address, Range("A1").Offset(i, j).Value

        'セルの値を取ってきて、先頭と末尾について調べ、必要に応じて " をつける
        cell_value = Range("A1").Offset(i, j).Value
        If InStr(1, cell_value, """") <> 1 Then
            cell_value = """" & cell_value
        End If
        If InStrRev(cell_value, """") <> Len(cell_value) Then
            cell_value = cell_value & """"
        End If

        row_text = row_text & "," & cell_value
    Next
    '行全体の調査が終わったのでこの行の調査で最終的に得られた文字列を書き込む
    ts.WriteLine Mid(row_text, 2)
Next

'すべての行での書き込みを終えたので終了処理

'ファイル書き込み関連のオブジェクトの後処理
ts.Close
Set ts = Nothing
Set fso = Nothing

'シート、ファイル関係のオブジェクトの後処理
wb.Close

Set rgAll = Nothing
Set ws = Nothing
Set wb = Nothing

End Sub


コメントをまあまあ丁寧に書いたので、 エクセルマクロ発展編1講座 https://forum.pc5bai.com/lesson/course/29/ 受講生くらいであれば分からないところは残ってもなんとか仕事にはなるだろうと思う。

テキストファイルのハンドリングもきちんと学んだうえであれば確実。
そこまで望むのであれば、以下まで学習を進めるのがおすすめ
エクセルマクロ外部連携講座 https://forum.pc5bai.com/lesson/course/61/

公開日時: 2023/05/31 13:15