列が1つ増えただけで転記ミス? CSVの列名を確かめてから書き込む方法

列が1つ増えただけで転記ミス? CSVの列名を確かめてから書き込む方法 業務自動化

毎月届くCSVに列が1つ増え、転記先の金額欄へ別の値が入ってしまった。「3列目は注文ID」と位置だけで決める処理は、入力形式の変化に弱くなります。

列名から位置を引き、その前に不足や重複を検出します。この記事では、すでにCSVを解析した後の二次元配列を使い、書き込む前に検証する独自コードを紹介します。CSV文字列を解析するコードや、本番シートへの書き込みは含めません。

位置が変わっても読めることと、何でも受け入れることは違う

列名を使えば並び替えには対応できます。ただし、必須列の欠落や同じ名前の重複を無視すると、誤ったデータが通ります。余分な列を許すか、決めた列以外は停止するかも、入力元との取り決めで選びます。この例は必須列を確認し、追加列は読み飛ばす方針です。

列の位置より、列名を確認。並び替え:名前から位置を引く。不足・重複:その場で停止する。入力値:IDと金額の形式を検証。追加列を許すかは、入力仕様で決める
図1:列の位置より、列名を確認。追加列を許すかは、入力仕様で決める
function selectOrders(rows) {
  if (!Array.isArray(rows) || rows.length < 1) throw Error('empty input');
  const header = rows[0];
  if (!Array.isArray(header) || header.some(x => typeof x !== 'string')) {
    throw Error('invalid header');
  }
  if (new Set(header).size !== header.length) throw Error('duplicate header');
  const required = ['order_id', 'amount'];
  const positions = required.map(name => {
    const index = header.indexOf(name);
    if (index < 0) throw Error('missing: ' + name);
    return index;
  });
  return rows.slice(1).map((row, i) => {
    if (!Array.isArray(row) || row.length !== header.length) {
      throw Error('width mismatch at data row ' + (i + 1));
    }
    const id = row[positions[0]];
    const amount = row[positions[1]];
    if (typeof id !== 'string' || !/^[A-Za-z0-9_-]{1,100}$/.test(id)) {
      throw Error('invalid order_id at data row ' + (i + 1));
    }
    if (typeof amount !== 'string' || !/^(0|[1-9][0-9]*)$/.test(amount)) {
      throw Error('invalid amount at data row ' + (i + 1));
    }
    if (!Number.isSafeInteger(Number(amount))) throw Error('amount too large');
    return {order_id: id, amount: Number(amount)};
  });
}

金額は非負整数の文字列だけを許す例です。通貨記号、小数、負数、桁区切りには対応しません。注文IDの先頭0は文字列として保持します。実際の入力仕様に合わせて、許す形式を先に決めてください。

全件を検証してから、書き込みを始める

1行目を登録し、2行目で入力エラーになると途中までの結果が残ります。上の関数は、配列全体が検証を通ったときだけ結果を返します。呼び出し元は、その後に書き込みへ進むようにします。ただし、書き込み中の障害まで一括で取り消す仕組みではありません。

書き込みは、検証の後。読み取る:CSVを二次元配列へ。全件を検証:列名・行幅・値の形式。保存へ進む:途中の保存失敗は別に設計。入力検証は、保存処理の原子性を保証しない
図2:書き込みは、検証の後。入力検証は、保存処理の原子性を保証しない
入力例このコードの扱い
amount, order_id と並び替え列名で対応して読み取る
order_id列がない書き込み前に停止
order_idが2列ある重複した列名として停止
注文IDが000123文字列のまま保持
金額が1,000や-10この例の入力仕様では停止

列名の空白や表記変更を、黙って直さない

「注文ID」と「order_id」を自動で同じ列と見なすと便利ですが、入力元の変更を見逃すことがあります。この例は完全一致です。別名を認める場合は対応表を管理し、想定外の列は記録して担当者へ確認します。

RFC 4180には、カンマや改行を含む値の扱いが説明されています。CSV文字列を単純なsplitで分割せず、入力形式に対応するパーサーで二次元配列にしてから、このような業務上の検証を行います。

確認した範囲を分けて使う

掲載した純粋関数は、列の並び替え、追加、不足、重複、行幅、先頭0、金額形式、巨大な数値などをローカルのNode.jsで確認しています。実際のCSVパーサー、Google Sheetsへの保存、同時実行、文字コードは検証範囲外です。業務へ組み込む際は、それぞれを検証用データで確かめます。

入力が変わったときに止まることは、自動化の失敗とは限りません。誤った値を静かに広げる前に、どの入力が想定と違うかを担当者へ渡せる設計にしてください。

参考資料・確認範囲

2026年11月2日確認。本文の例・図・ひな型は本記事用に作成したものです。以下は、設計や事例の背景として参照した一次資料です。

RFC 4180:CSVの一般的な形式

コメント

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