CSVをカンマで割るだけでは足りない
表データをJSONへ移すとき、各行を改行で分け、各セルをカンマで分けるだけでは、セルの中にあるカンマや改行を区切りと取り違えます。たとえば "music, video" は一つの値ですが、単純な split(',') では二つの値になります。引用符で囲まれた複数行の文章も、行の区切りで分割すると崩れます。
ToolShedのCSV→JSONは、先頭行を列名として読み、後続行をオブジェクト配列へ変換します。仕事の表を移すときは、変換後のJSONだけでなく、列名・列数・値の型も一緒に確認する必要があります。
パーサーの考え方を比べる
表は横にスクロールできます。
| 同じ入力を処理 | 単純な改行・カンマ分割 | 引用符を読む処理 |
|---|---|---|
| CSVの物理行 | 4行として読む(ヘッダー+データ断片3行) | ヘッダー+データ2件として読む |
| Sheer Clipのnote | "music と video" に分裂 | music, video の1値 |
| ToolShedのnote | "line one と次の行に分裂 | 改行を含む1値。二重引用符も復元 |
引用符を扱う処理では、文字を1つずつ見て「引用符の内側か」を記録します。内側のカンマと改行は値として残し、連続した二重引用符は値中の引用符1つとして読みます。外側にあるカンマと改行だけをセル・行の区切りにします。引用符内の文字を残す必要があるため、単純分割よりこの方式が要件に合います。今回のサンプルでは両方を同じ入力で比べ、2件のデータと値が保たれることをテストします。
次の入力は、引用符内の改行を含むため物理的には4行、ヘッダーを除く論理データは2件です。単純分割では1件目のnoteがカンマで2セルに分かれ、2件目は改行で別の断片になります。
name,count,note
Sheer Clip,2,"music, video"
ToolShed,3,"line one
line ""two"""
列名は最初の行から取得し、各データ行では列名の数だけ値を読みます。CSVはテキストなので、数値に見える 2 もJSONでは文字列の "2" になります。計算に使う場合は、受け取った後に列ごとの型変換を検討してください。
独立テストで再現する
ToolShedの実装からコピーしたTypeScriptファイルとNode.js標準テストを使います。例の1件目にはカンマを含む値、2件目には改行と二重引用符を含む値を入れました。
- サンプルとテストを保存する
CSV変換のサンプルとテストファイルを同じフォルダへ保存します。
- Node.js 24でテストを実行する
そのフォルダで
node --experimental-strip-types --test --test-isolation=none toolshed-csv-json.test.mjsを実行します。TypeScriptの型注釈を除いてNode.jsから直接読み込む指定です。 - 比較と変換を確認する
5つのテストが引用符内のカンマ・改行・引用符、値の文字列化、往復、列の不足と余剰、同じ入力に対する単純分割との違いを検査します。
2件全体の出力は次のようになります。値は保たれますが、型情報はCSVに含まれないため、数値も文字列として表現されます。
[
{
"name": "Sheer Clip",
"count": "2",
"note": "music, video"
},
{
"name": "ToolShed",
"count": "3",
"note": "line one\nline \"two\""
}
]
このサンプルはアプリ本体から抽出した関数のコピーで、UIや本番サイトのデータ処理を呼び出すものではありません。手元で仕組みを試すための独立した例です。
テストで確かめた結果
Node.js v24.19.0で独立テスト5件が成功しました。引用符内のカンマは一つのセルに残り、引用符内の改行と二重引用符も復元されます。JSON→CSV→JSONでは、文字列として表せる値とヘッダーの並びを保てました。同じ入力を単純分割した比較では、ヘッダーを除くデータ断片が2件ではなく3件になり、最初のnoteも "music と video" に分かれました。
列数の違いも実際の関数に合わせて検査しています。列名より値が少ない行では不足セルが空文字になります。一方、値が多い行では余剰セルが出力JSONへ入りません。列数の不一致をエラーとして止める挙動ではないため、変換前に各データ行のセル数を列名の数と照合してください。
この結果を自分のCSVへ当てはめるなら、まず先頭行の列名、その後に数行の入力・出力を比較し、日付・数値・空欄が意図した形かを確かめます。元データを上書きする前に、変換後の値を使う側でも確認するのが安全です。
使う前に確認したいこと
- 先頭行が列名として扱われるため、ヘッダーのないCSVはそのままでは同じ意味に変換できません。
- すべてのCSV値は文字列です。数値演算や日付比較が必要なら、用途に応じて型を決め直します。
- 同じ列名が重複する場合は、後の値が同じオブジェクトのキーを上書きします。
- 余剰セルは現在の処理で捨てられます。行ごとの列数を事前に点検してください。
- このテストは区切りや引用符の代表例を扱いますが、あらゆる入力元のCSV方言を保証するものではありません。
ToolShedで使う場合は、対象ツールのCSV入力へ貼り付け、JSON出力を見てからコピーします。変換自体の説明はToolShedの使い方にまとめています。
参照した実装
コピー元はToolShedのソースリポジトリ webtool のHEAD 88a9ca686 にある packages/tools/src/text/csv-json.ts です。ブログのサンプルはこのファイルをそのまま配置し、変換関数の挙動をNode.jsテストで確かめる構成にしました。
テストは入力例を指定して実行できる確認範囲です。ToolShedの全機能や、本番環境でのファイル保存・通信までをテストするものではありません。