JavaScript Tips | 配列ユーティリティ:CSV 変換

JavaScript JavaScript
スポンサーリンク

テーマの整理:「配列ユーティリティ × CSV 変換」とは何か

ここで扱うのは、「JavaScript の配列(オブジェクト配列)を、業務でそのまま使える CSV 文字列に変換するユーティリティ」です。 CSV は、Excel・スプレッドシート・BI ツール・他システム連携など、実務でめちゃくちゃよく使われます。

だからこそ、

配列 → CSV CSV → ダウンロード CSV → 別システムへ送信

この流れを、毎回手書きではなく「ユーティリティ」として持っておくと、仕事がかなり楽になります。

基本コンセプト:オブジェクト配列を「ヘッダー+行」に落とし込む

どんな配列を CSV にするのか

業務でよくある形は、こんな配列です。

const rows = [
  { id: 1, name: "Alice",  email: "alice@example.com" },
  { id: 2, name: "Bob",    email: "bob@example.com" },
  { id: 3, name: "Carol",  email: "carol@example.com" },
];
JavaScript

これを CSV にすると、こういうイメージになります。

id,name,email
1,Alice,alice@example.com
2,Bob,bob@example.com
3,Carol,carol@example.com

つまり、

1 行目が「ヘッダー(列名)」 2 行目以降が「データ行」

という構造です。

ヘッダーをどう決めるか

一番シンプルなのは、「最初のオブジェクトのキーをヘッダーにする」方法です。

const header = Object.keys(rows[0]); // ["id", "name", "email"]
JavaScript

業務では「列順を指定したい」「表示名を変えたい」ことも多いので、 後で「ヘッダーを明示的に渡す」形にも拡張できるようにしておくとよいです。

実装:配列 → CSV 文字列の基本ユーティリティ

コア関数:toCsv

まずは、初心者でも読めるレベルで、ちゃんと業務で使える CSV 変換関数を書きます。

function escapeCsvValue(value) {
  if (value === null || value === undefined) {
    return "";
  }

  const str = String(value);

  const needsQuote =
    str.includes(",") ||
    str.includes('"') ||
    str.includes("\n") ||
    str.includes("\r");

  if (!needsQuote) {
    return str;
  }

  const escaped = str.replace(/"/g, '""');
  return `"${escaped}"`;
}

function toCsv(rows, headerKeys) {
  if (!Array.isArray(rows) || rows.length === 0) {
    return "";
  }

  const keys =
    Array.isArray(headerKeys) && headerKeys.length > 0
      ? headerKeys
      : Object.keys(rows[0]);

  const headerLine = keys.join(",");

  const dataLines = rows.map((row) => {
    return keys
      .map((key) => escapeCsvValue(row[key]))
      .join(",");
  });

  return [headerLine, ...dataLines].join("\n");
}
JavaScript

重要ポイントをかみ砕いて説明

escapeCsvValue が「1 つのセルの値を CSV 用に安全にする」役割です。 カンマ・ダブルクォート・改行が含まれる場合は、ダブルクォートで囲み、内部の """ にエスケープします。 null や undefined は空文字にしておくと、Excel などで扱いやすいです。

toCsv は「配列全体を CSV 文字列にする」関数です。 headerKeys が渡されていればそれを列順として使い、なければ最初の行のキーを使います。 各行は「キー順に値を取り出して、カンマで結合」して作ります。 最後に、ヘッダー行+データ行を \n で結合して 1 つの文字列にします。

この時点で、かなり実務でそのまま使えるレベルになっています。

例題 1:ユーザー一覧を CSV にしてコンソールに出す

コード

const users = [
  { id: 1, name: "Alice",  email: "alice@example.com" },
  { id: 2, name: "Bob",    email: "bob@example.com" },
  { id: 3, name: "Carol",  email: "carol@example.com" },
];

const csv = toCsv(users);

console.log(csv);
JavaScript

出力イメージはこうなります。

id,name,email
1,Alice,alice@example.com
2,Bob,bob@example.com
3,Carol,carol@example.com

ここでのポイントは、

配列のキー順がそのまま列順になっている。 特別な文字がないので、エスケープもシンプル。

というところです。

例題 2:日本語やカンマ・改行を含む値を CSV にする

シナリオ

業務では、名前や備考に日本語・カンマ・改行が普通に入ります。 これを正しく CSV にしないと、Excel で開いたときに列がズレます。

コード

const items = [
  { id: 1, name: "りんご",  note: "赤い, おいしい" },
  { id: 2, name: "バナナ",  note: "黄色\n南国フルーツ" },
  { id: 3, name: "ぶどう",  note: "「高級」フルーツ" },
];

const csv = toCsv(items);

console.log(csv);
JavaScript

出力イメージ(概念的):

id,name,note
1,りんご,"赤い, おいしい"
2,バナナ,"黄色
南国フルーツ"
3,ぶどう,"""高級""フルーツ"

ここでの重要ポイントは、

カンマを含む note は "..." で囲まれている。 改行を含む note も "..." で囲まれていて、1 セルとして扱われる。 ダブルクォートを含む note は "" にエスケープされている。

このエスケープができていないと、CSV は「見た目はそれっぽいけど壊れている」状態になります。 業務で CSV を扱うなら、ここは絶対に押さえておきたいところです。

例題 3:列順・列名を指定して CSV を作る

シナリオ

業務では、「出力する列の順番」「列名」を仕様で決められていることが多いです。 内部のキー名と CSV のヘッダー名を変えたいこともあります。

列順だけ指定する場合

const users = [
  { id: 1, name: "Alice",  email: "alice@example.com" },
  { id: 2, name: "Bob",    email: "bob@example.com" },
];

const csv = toCsv(users, ["name", "email", "id"]);

console.log(csv);
JavaScript

出力イメージ:

name,email,id
Alice,alice@example.com,1
Bob,bob@example.com,2

列名も変えたい場合(ラッパーを作る)

function toCsvWithHeaderMap(rows, headerMap) {
  const keys = Object.keys(headerMap); // ["id", "name", "email"]
  const headerLine = keys.map((k) => headerMap[k]).join(",");

  const dataLines = rows.map((row) => {
    return keys
      .map((key) => escapeCsvValue(row[key]))
      .join(",");
  });

  return [headerLine, ...dataLines].join("\n");
}

const users = [
  { id: 1, name: "Alice",  email: "alice@example.com" },
  { id: 2, name: "Bob",    email: "bob@example.com" },
];

const headerMap = {
  id: "ユーザーID",
  name: "氏名",
  email: "メールアドレス",
};

const csv = toCsvWithHeaderMap(users, headerMap);

console.log(csv);
JavaScript

出力イメージ:

ユーザーID,氏名,メールアドレス
1,Alice,alice@example.com
2,Bob,bob@example.com

ここでのポイントは、

内部のキー(id, name, email)と、CSV のヘッダー名(日本語)が分離されている。 仕様変更でヘッダー名が変わっても、headerMap だけ直せばよい。

というところです。

CSV 変換ユーティリティで意識してほしい重要ポイント

「壊れた CSV」を絶対に出さない

CSV は「ただのテキスト」なので、壊れていても一見それっぽく見えます。 でも、Excel や他システムに読み込ませたときに列がズレたり、行が分割されたりして地獄になります。

だからこそ、

カンマ・ダブルクォート・改行を含む値は必ずエスケープする。 null / undefined はどう扱うかを決めておく(空文字にするのが無難)。 ヘッダー行とデータ行の列数が必ず一致するようにする。

このあたりは「CSV ユーティリティの品質」として、かなり重要です。

「文字コード」と「改行コード」を意識する(軽く触れておく)

ブラウザでダウンロードする CSV は、だいたい UTF-8+\n で問題ありません。 Windows の古い環境や一部ツールでは、Shift_JIS や \r\n が求められることもあります。

初心者のうちは、

まずは UTF-8+\n で作る。 もし「文字化けする」「改行がおかしい」と言われたら、そこから調べる。

くらいのスタンスで十分です。

手を動かして「配列 → CSV」の感覚をつかむ

次のコードを実行して、 「シンプルな配列」「日本語・カンマ・改行を含む配列」「列順指定」の CSV 出力を体感してみてください。

function escapeCsvValue(value) {
  if (value === null || value === undefined) {
    return "";
  }

  const str = String(value);

  const needsQuote =
    str.includes(",") ||
    str.includes('"') ||
    str.includes("\n") ||
    str.includes("\r");

  if (!needsQuote) {
    return str;
  }

  const escaped = str.replace(/"/g, '""');
  return `"${escaped}"`;
}

function toCsv(rows, headerKeys) {
  if (!Array.isArray(rows) || rows.length === 0) {
    return "";
  }

  const keys =
    Array.isArray(headerKeys) && headerKeys.length > 0
      ? headerKeys
      : Object.keys(rows[0]);

  const headerLine = keys.join(",");

  const dataLines = rows.map((row) => {
    return keys
      .map((key) => escapeCsvValue(row[key]))
      .join(",");
  });

  return [headerLine, ...dataLines].join("\n");
}

function demo() {
  const users = [
    { id: 1, name: "Alice",  email: "alice@example.com" },
    { id: 2, name: "Bob",    email: "bob@example.com" },
  ];

  console.log("=== basic ===");
  console.log(toCsv(users));

  const items = [
    { id: 1, name: "りんご",  note: "赤い, おいしい" },
    { id: 2, name: "バナナ",  note: "黄色\n南国フルーツ" },
    { id: 3, name: "ぶどう",  note: "「高級」フルーツ" },
  ];

  console.log("=== with japanese & special chars ===");
  console.log(toCsv(items));

  console.log("=== custom column order ===");
  console.log(toCsv(users, ["name", "email", "id"]));
}

demo();
JavaScript

まとめ:CSV 変換ユーティリティで「配列をそのまま業務連携の材料にする」

配列 → CSV は、 「コードの世界の配列を、Excel や他システムが理解できる形に変える橋渡し」です。

プロジェクトに例えば次のような形で置いておくイメージです。

export function toCsv(rows, headerKeys) { ... }
export function escapeCsvValue(value) { ... }
JavaScript

そして、

一覧データのエクスポート、 レポート出力、 他システムへの連携ファイル生成

といったところでは、必ずこのユーティリティを通す。

こう決めておくと、「毎回 CSV を手書きする」「壊れた CSV を量産する」といった事故が減り、 配列データがそのまま“業務の材料”として使えるようになっていきます。

CSV は地味だけど、仕事では主役級です。 そこにちゃんとしたユーティリティを用意しておくのは、かなり“仕事ができるエンジニア”の動き方です。

タイトルとURLをコピーしました