VBAでExcelの日報データをCSVファイルに書き出す

フォーム形式のExcelファイルから必要な項目を抽出してCSVを生成するVBAコードを解説します。シートごとに1日分の日報が記録されたファイルを想定した実践的なサンプルです。

想定するExcelの構造

以下のような日報ファイルを想定します。

  • シート名:「2025-01-06」「2025-01-07」…(日付ごとのシート)
  • 各シートの構造(フォーム形式):
B2セル:日付
B3セル:担当者名
B5セル:作業内容
B7セル:訪問先(外出した場合)
B9セル:翌日の予定
B11セル:備考

このフォームから必要な項目を抽出し、以下のようなCSVを生成します。

日付,担当者,作業内容,訪問先,翌日予定,備考
2025-01-06,田中,〇〇の対応,△△社,,次回フォロー
2025-01-07,田中,月次レポート作成,,,送付完了

コード

Sub 日報をCSVに出力()

    Dim ws As Worksheet
    Dim outputPath As String
    Dim fileNum As Integer
    Dim lineData As String
    Dim sheetCount As Long

    ' 出力先のCSVファイルパスを設定
    outputPath = ThisWorkbook.Path & "\日報_" & Format(Now, "yyyymmdd") & ".csv"

    ' ファイルを開く(新規作成)
    fileNum = FreeFile
    Open outputPath For Output As #fileNum

    ' ヘッダー行を書き込む
    Print #fileNum, "日付,担当者,作業内容,訪問先,翌日予定,備考"

    sheetCount = 0

    ' 全シートを順番に処理する
    For Each ws In ThisWorkbook.Worksheets

        ' 日付形式のシート名のみ処理(「集計」などのシートはスキップ)
        ' シート名が10文字(YYYY-MM-DD)かどうかで判定
        If Len(ws.Name) = 10 Then

            ' 各セルから値を取得
            Dim dateVal As String
            Dim staffName As String
            Dim workContent As String
            Dim visitDest As String
            Dim nextPlan As String
            Dim remarks As String

            dateVal    = CStr(ws.Range("B2").Value)
            staffName  = CStr(ws.Range("B3").Value)
            workContent = CStr(ws.Range("B5").Value)
            visitDest  = CStr(ws.Range("B7").Value)
            nextPlan   = CStr(ws.Range("B9").Value)
            remarks    = CStr(ws.Range("B11").Value)

            ' カンマや改行を含む値をダブルクォートで囲む
            dateVal     = EscapeCSV(dateVal)
            staffName   = EscapeCSV(staffName)
            workContent = EscapeCSV(workContent)
            visitDest   = EscapeCSV(visitDest)
            nextPlan    = EscapeCSV(nextPlan)
            remarks     = EscapeCSV(remarks)

            ' 1行分のデータを結合してCSVに書き込む
            lineData = dateVal & "," & staffName & "," & workContent & "," & _
                       visitDest & "," & nextPlan & "," & remarks
            Print #fileNum, lineData

            sheetCount = sheetCount + 1
        End If

    Next ws

    ' ファイルを閉じる
    Close #fileNum

    MsgBox sheetCount & "件の日報を出力しました。" & vbCrLf & outputPath

End Sub

' カンマ・ダブルクォート・改行を含む値をCSV用にエスケープする関数
Function EscapeCSV(value As String) As String
    ' ダブルクォートを二重にする
    value = Replace(value, """", """""")
    ' カンマ・改行・ダブルクォートが含まれる場合はダブルクォートで囲む
    If InStr(value, ",") > 0 Or InStr(value, Chr(10)) > 0 Or InStr(value, """") > 0 Then
        value = """" & value & """"
    End If
    EscapeCSV = value
End Function

コードの解説

ファイルへの書き込み:Open〜Print〜Close

VBAでテキストファイルを書くときは OpenPrintClose を使います。

fileNum = FreeFile           ' 使用可能なファイル番号を取得
Open outputPath For Output As #fileNum  ' 書き込みモードでファイルを開く
Print #fileNum, "書きたいテキスト"     ' 1行書き込む
Close #fileNum               ' ファイルを閉じる(必ず実行する)

FreeFile は「今使われていないファイル番号」を返します。複数ファイルを同時に扱う場合の番号の衝突を防ぐために使います。

CSVのエスケープ処理

CSVで値にカンマが含まれていると、列の区切りと誤認識されます。対策として、カンマ・改行・ダブルクォートが含まれる値はダブルクォートで囲みます。ダブルクォート自体は二重("")にします。

これを EscapeCSV() という関数として切り出しておくことで、各列に対して同じ処理を再利用できます。

シートの判定方法

If Len(ws.Name) = 10 Then

「YYYY-MM-DD」形式のシート名は10文字なので、この条件で日報シートのみを処理対象にしています。

シート名の命名規則によっては、より厳密な判定が必要になる場合があります。たとえば先頭4文字が「2025」などの年であることをチェックする方法もあります。

If Len(ws.Name) = 10 And Left(ws.Name, 4) >= "2020" Then

文字コードの注意

このコードで生成されるCSVはExcelで開くことを想定したShift-JISで書き出されます。

Pythonや他のシステムに渡す場合、UTF-8を要求されることがあります。その場合はVBAではなくPythonでCSVを生成するほうが扱いやすいです。

import csv
# Pythonではエンコーディングを明示的に指定できる
with open("output.csv", "w", newline="", encoding="utf-8-sig") as f:
    writer = csv.writer(f)
    writer.writerow(["日付", "担当者", "作業内容"])

utf-8-sig はBOM付きUTF-8で、ExcelでCSVを開いても文字化けしない形式です。

セルの位置が違う場合の調整方法

日報のフォームが自社のものと異なる場合は、セルの参照箇所を変更します。

' B2ではなくC3にある場合
dateVal = CStr(ws.Range("C3").Value)

' 結合セルの場合は左上のセルを指定
workContent = CStr(ws.Range("B5").Value)  ' B5:E5が結合されていてもB5で取得できる

まとめ

Dir() でフォルダを走査する方法と組み合わせると、「複数フォルダに分散した日報ファイルを一括でCSVにまとめる」ような処理も実現できます。フォーム形式のExcelからデータを抽出してCSVに変換する仕組みを持つことで、他のシステムへのデータ連携がスムーズになります。