短いコードで「CSVの読み込み(文字列→配列/オブジェクト)」と「書き込み(配列/オブジェクト→文字列)」を扱えるユーティリティです。標準ライブラリだけで動き、カンマ・ダブルクオート・改行に対応します。
コード
// CSVを配列の配列へ変換(1行=1配列)
export function parseCSV(csv, { delimiter = ',', trim = true } = {}) {
const rows = [];
let row = [];
let field = '';
let i = 0;
let inQuotes = false;
while (i < csv.length) {
const ch = csv[i];
if (inQuotes) {
if (ch === '"') {
// 連続する "" はエスケープされた " を意味する
if (csv[i + 1] === '"') {
field += '"';
i += 2;
continue;
}
inQuotes = false;
i++;
continue;
}
field += ch;
i++;
continue;
}
if (ch === '"') {
inQuotes = true;
i++;
continue;
}
if (ch === delimiter) {
row.push(trim ? field.trim() : field);
field = '';
i++;
continue;
}
if (ch === '\n') {
row.push(trim ? field.trim() : field);
rows.push(row);
row = [];
field = '';
i++;
continue;
}
if (ch === '\r') {
// 先に \r が来て次が \n の場合(Windows改行)をスキップ
if (csv[i + 1] === '\n') {
i += 2;
} else {
i++;
}
row.push(trim ? field.trim() : field);
rows.push(row);
row = [];
field = '';
continue;
}
field += ch;
i++;
}
// 最終フィールド・最終行を反映
if (field !== '' || inQuotes || row.length > 0) {
row.push(trim ? field.trim() : field);
rows.push(row);
}
return rows;
}
// ヘッダー行をキーに、配列の配列→配列のオブジェクトへ
export function toObjects(rows) {
if (!rows.length) return [];
const [header, ...body] = rows;
return body.map(r => {
const obj = {};
for (let i = 0; i < header.length; i++) {
obj[header[i]] = r[i] ?? '';
}
return obj;
});
}
// 配列の配列からCSV文字列へ(各フィールドを適切にエスケープ)
export function stringifyRows(rows, { delimiter = ',' } = {}) {
const escapeField = (val) => {
const s = val == null ? '' : String(val);
const needsQuote =
s.includes('"') || s.includes('\n') || s.includes('\r') || s.includes(delimiter);
const escaped = s.replace(/"/g, '""');
return needsQuote ? `"${escaped}"` : escaped;
};
return rows
.map(row => row.map(escapeField).join(delimiter))
.join('\n');
}
// オブジェクト配列をCSVへ(キー順でヘッダーを生成)
export function stringifyObjects(items, { delimiter = ',' } = {}) {
if (!items.length) return '';
const keys = Array.from(
items.reduce((set, obj) => {
Object.keys(obj).forEach(k => set.add(k));
return set;
}, new Set())
);
const rows = [
keys,
...items.map(obj => keys.map(k => obj[k] ?? '')),
];
return stringifyRows(rows, { delimiter });
}
JavaScript使い方
読み込み(CSV文字列 → 配列/オブジェクト)
const csv = `name,age,note
"田中,太郎",28,"改行
を含むメモ"
佐藤,31,"ダブルクオート ""あり"""`;
const rows = parseCSV(csv); // 2次元配列
const list = toObjects(rows); // [{ name: '田中,太郎', age: '28', note: '改行\nを含むメモ' }, ...]
console.log(list);
JavaScript書き込み(配列/オブジェクト → CSV文字列)
const items = [
{ name: '田中,太郎', age: 28, note: '改行\nOK' },
{ name: '佐藤', age: 31, note: 'ダブルクオート " あり' },
];
const csvOut = stringifyObjects(items);
console.log(csvOut);
/*
name,age,note
"田中,太郎",28,"改行
OK"
佐藤,31,"ダブルクオート "" あり"
*/
JavaScript特徴と注意点
- 対応: カンマ、改行、CRLF、ダブルクオートのエスケープ(””)をサポート。
- オプション:
delimiterで区切り変更(例:';'や'\t')、trimでフィールドの前後空白を除去。 - 未対応の範囲: コメント行、数値/日時の型推論、大規模ファイルのストリーミング処理は対象外。大きなCSVはストリームや既存ライブラリ(例: csv-parse, Papaparse)の利用を検討してください。
- ヘッダー生成:
stringifyObjectsは複数オブジェクトのキーを集約してヘッダーを作成。不足キーは空文字で埋めます。

