3秒でわかる
Node.js で CSV を読み解くための定番ライブラリ。引用符や改行を含む値も規則どおりに扱え、大きなファイルをストリームで処理できます。
もう少し詳しく
どういうものか
csv-parse は、CSV のテキストを行と列の構造へ変換する Node.js のライブラリである。CSV を扱う csv パッケージ群の一部で、書き出し側の csv-stringify、変換の stream-transform と組で使われる。
使い方は 3 通り用意されている。文字列をまとめて配列にする同期版、コールバックで受け取る版、そしてストリームとして流す版である。ファイルサイズが大きい場合はストリーム版を選ぶ。
なぜ必要か
CSV は見た目が単純なので split(",") で足りると思われがちだが、実際の仕様は素朴な分割では扱えない。値の中にカンマが入る場合は引用符で囲まれ、値の中に引用符が入る場合は二重にして表す。値の中に改行が入ることもあり、その行だけ 2 行以上に見える。
id,name,note
1,"佐藤, 太郎","彼はこう言った ""おはよう"""
2,"田中","住所の途中で
改行が入る値"このデータを split("\n") と split(",") で処理すると、1 行目から崩れる。csv-parse はこれらの規則を実装しているため、正しい構造で取り出せる。
具体例
import { parse } from "csv-parse/sync";
import fs from "node:fs";
const text = fs.readFileSync("orders.csv", "utf8");
const rows = parse(text, {
columns: true, // 1 行目をヘッダとして扱い、<a href="/glossary/object" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">オブジェクト</a>で返す
skip_empty_lines: true,
trim: true,
cast: true, // 数値らしき値を数値へ変換する
});
console.log(rows[0]); // { id: 1, name: '佐藤', total: 3200 }大きなファイルはストリームで流す。全体をメモリに載せずに済む。
import { parse } from "csv-parse";
import fs from "node:fs";
const parser = fs.createReadStream("large.csv").pipe(
parse({ columns: true, skip_empty_lines: true })
);
let count = 0;
for await (const record of parser) {
count += Number(record.total);
}
console.log(count);つまずきやすいところ
読み込み口の取り違えが多い。同期版は csv-parse/sync から、ストリーム版は csv-parse から parse を読み込む。取り違えると「関数が返す型が違う」形でつまずく。
文字コードも定番の落とし穴になる。Excel が書き出した CSV は Shift_JIS のことがあり、utf8 として読むと日本語が化ける。iconv-lite で変換してから渡す。先頭に BOM が付く場合は bom オプションを有効にする。
区切り文字がタブやセミコロンのファイルは delimiter で指定する。cast を有効にするのは便利だが、007 のような先頭ゼロの伝票番号まで数値の 7 に変えてしまうため、ID を含むデータでは列ごとに変換関数を指定する方が安全である。
覚え方
CSV を自前で分割したくなったら、値の中のカンマと引用符と改行の 3 つを思い出す。この 3 つが出た時点で、ライブラリに任せた方が速い。