CSVをSplitだけで読めない理由

LWP | CSVをSplitだけで読めない理由

CSVをSplitだけで読めない理由

カンマ・引用符・改行を、8枚の図で読み解く

ストーリー

「元の表は3項目なのに、取り込むと4つに」。フナさんの相談を受け、シャケもんが分割結果を確認。アユさんも加わり、文字の読み方から原因を探ります。

VBAの変数と短いコードを読める方向け。前半はCSVの原理、後半はTakiLib Ver 3.5.4の実装例です。会話は説明用の物語です。

1 3項目のはずが、4つに?

CSV本文A,"B,C",DをSplitで分けるとA、"B、C"、Dの4要素になる。正しい読み取りはA、B,C、Dの3項目。シャケもんは右の図へ顔を向けて確認する。

図1|引用された項目の中にも、カンマがある。

2 同じ文字でも、状態で意味が変わる

アユさんとシャケもんが引用の外・引用の中という読み取り状態を確認する。項目先頭の引用符で中へ入り、閉じる引用符で外へ戻る。二重引用符の詳細は図4で扱う。

図2|まずは読み方の概念図。実装には項目の確定や先読みも必要。

3 カンマを切るのは、引用の外

引用の外のA,Bは2項目。引用された"B,C"はカンマを含む1項目。フナさんが元の3項目と読み取り結果を照合する。

図3|項目を分けるカンマと、項目に残すカンマを区別する。

4 二つの引用符で、一文字を表す

CSV本文"A""B",Cの先頭項目を、開始引用符・A・引用符2個・B・終了引用符の6文字に分解する。読み取り結果はA"BとCの2項目。

図4|囲みの引用符を外し、項目中の二重引用符は一文字へ戻す。

5 見た目の2行が、1レコードになる

CSVの引用された項目でAの後に改行し、次の物理行にB",Cが続く。読み取り結果は、改行を含むAとBの項目、およびCの項目からなる1レコード。

図5|先に改行で分割すると、引用中の項目を途中で切ってしまう。

6 引用符が閉じる前に、終わったら?

引用符が閉じていないCSV本文"A,BをTakiLib csvParseTextAsCsv Ver 3.5.4で読むとエラー2510になる。入力の終わりと、項目の完成を区別する。

図6|エラー番号と未完成入力の扱いは、今回確認した実装の動作。

7 返るのは、行ごとの配列

入力の1行目A,Bと2行目C,D,Eを読むと、行0の2要素配列と行1の3要素配列を持つ入れ子配列が返る。フナさんが取り込み先の列数との照合を促す。

図7|読めたことと、各行の列数が業務に合うことは別に確認する。

8 原理・実装・業務条件を、そろえて確認

A,BとC,Dの間に空行がある入力を今回の実装へ渡すと2レコードになる。アユさんが実装差、シャケもんが実際の動作、フナさんが業務上の必要性を確認する。

図8|空行を読み飛ばしてよいかは、データの意味に照らして決める。

まとめ

Splitは指定した区切り文字で文字列を分けます。CSVでは、引用の中か外かによって、同じカンマや改行の役割が変わります。読み取り結果を元データと照合し、列数や空行の扱いまで確かめることが大切です。

今回の仕掛け

アユさんが持ち込むのは、状態を区別して文字を読む考え方。シャケもんは実装と試験結果を確認し、フナさんは必要な列や空行の意味を判断します。三人の知識と確認結果を合わせて、使える読み取り方を探しています。

図2は理解のための簡略図です。実際のcsvParseTextAsCsvは、項目の読み取り状態に加え、二重引用符の先読み、項目・レコードの確定、終端や不正入力の判定を行います。

実装を選ぶときの確認

  • 今回の実装は、行ごとの配列を持つ入れ子配列を返します。列数の異なる行も受け取るため、取り込み先に必要な列数は別途照合します。

  • 途中の連続する改行は読み飛ばします。末尾の改行の有無は受け入れますが、閉じる引用符の直後に空白がある入力は、今回の試験でエラー2507になりました。

  • 図6~8はTakiLib Ver 3.5.4の限定した動作確認です。任意のCSVへの完全準拠を示すものではありません。区切り文字を公開変数に設定する実装なので、独立した局所状態だけで動く再入可能なパーサーとも説明できません。

今回のソースコードのサンプル

サンプルコード Splitの分割結果を確かめる

01

Public Sub Test_Main()

02

    Dim x_csv As String

03

    x_csv = "A,""B,C"",D"

04

    Dim x_parts As Variant

05

    x_parts = Split(x_csv, ",")

06

    Debug.Print UBound(x_parts) - LBound(x_parts) + 1

07

    Dim x_part As Variant

08

    For Each x_part In x_parts

09

        Debug.Print "[" & x_part & "]"

10

    Next

11

End Sub

コードの説明

x_csvがCSV本文、x_partsがSplitの戻り値です。UBoundとLBoundから要素数を求め、For Eachで各要素を角括弧に入れて表示します。

入力・準備

Windows版ExcelのVBEで標準モジュールへ全文を貼り付け、Test_Mainを実行します。結果はイミディエイトウィンドウで確認できます。TakiLibの導入は不要です。

結果

先頭に4、続いて[A]、["B]、[C"]、[D]がそれぞれ別の行へ表示されます。CSVとして期待する3項目とは一致しません。

読むポイント

CSV本文は A,"B,C",D です。VBAコードの文字列リテラルでは、その引用符一文字を "" と書きます。CSVの囲みと、VBAで引用符を書くための二重化を混同しないようにしましょう。

出典メモ

  • RFC 4180:CSVの形式 第2節。引用中のカンマ・改行・二重引用符の説明を参照。Informational文書です。

  • Microsoft Learn:Split関数。引数と戻り値を参照。

  • TakiLib Ver 3.5.4のcsvParseTextAsCsvと依存処理を確認。2026年9月12日、Windows版Excel 16.0/Build 20326で、本文の入力例と境界条件10ケース、およびSplitとの比較を実行しました。改行例はCRLFで確認しています。ファイルの文字コード判定や外部システムへの取り込みは今回の検証対象に含めていません。

Copyright © 2026 LWP 山中 一弘

本資料は、出典を明記いただければ、商用・非商用を問わず、ご自由に複製・改変・再配布していただけます。なお、著作権表示は改変せず、そのまま記載してご利用くださいますようお願いいたします。