データ記述フォーマットのCSV
これをJavaScriptで次のように扱いたいです。
- CSVをファイルなどから読み込み
- それを配列・連想配列へと変換
- 余計なライブラリとかも入れたくない
やってみたら意外と簡単だったので、
JSだけでCSVを配列に変換する方法を紹介します。
このページの目次
ここで想定するCSVのフォーマットについて
ここでは次のフォーマットを前提にします。
▼ 解析対象のCSV例
1 2 3 4 5 6 7 |
"name","hex","rgb" "Red","#FF0000","255,0,0" "Orange","#FFA500","255,165,0" "Yellow","#FFFF00","255,255,0", "Lime","#00FF00","0,255,0" "Blue","#0000FF","0,0,255" "Indigo","#4B0082","75,0,130" |
▼ 前提条件
- 文字コードは基本的にUTF-8
- 1行目にあるのがヘッダー
- 値は " で囲むこと
- 各値は , で区切ること
CSVにもいろいろ方言があるみたいですが、ここでは汎用的に使えそうな値のダブルクォート囲み+コンマ区切りのCSVを想定しています。
また1行目の "name","hex","rgb" はヘッダーです。存在しない場合もあるんですが、ここで紹介する方法では必須となるので注意してください
JSによるCSVを配列・連想配列に変換する関数コード例
では本題に入っていきます。
CSVを配列などに変換する方法について
次のようなコードを書くことで可能です。
▼ CSVをJS配列・連想配列に変換する関数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
function csvToArray(str, noHeader=false,quote="\"",delimiter = ",") { /// ヘッダー行の値配列を取得 const headers = str.split('\n')[0].split(delimiter) /// 各行のテキスト配列を取得 const rows = str.slice(str.indexOf("\n") + 1) .split(/\n|\r\n|\r/) /// 各行の値配列・オブジェクトの配列に変換 /// noHeaderがfalseならヘッダーカラム名付きで、 /// trueならカラム名なしの配列として返す const arr = rows.map(function (row) { const values = row.split(quote+delimiter+quote); const el = headers.reduce( function (obj, header, i) { const v = values[i].replaceAll('\"',"") if(noHeader){ obj.push(v) }else{ obj[header] = v; } return obj; }, (noHeader) ? [] : {} ); return el; }); // return the array return arr; } |
何をしてるかはコメントを見てください。
ここでのポイントは headers.redule(function(obj,header,i){...}) の部分。Array.reduceメソッドを使うと配列に対して連続的かつ順番に処理を行えます。
reduce() メソッドは、配列のそれぞれの要素に対して、順番通りに、ユーザーが提供した「縮小」コールバック関数を呼び出します。その際、直前の要素における計算結果の返値を渡します。配列のすべての要素に対して縮小関数を実行した結果が単一の値が最終結果になります。
引用元 : https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
ここでは headers に対してArray.reduceメソッドを適用し、ヘッダーカラム名をキーにした各行の値オブジェクトを簡単に得られるようにしています。(ただし noHeader = false の場合)
このcsvToArray関数の使い方コード例
例えばこんな感じに使えます。
▼ 実際に使ってみたコード例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/// CSVテキスト const csv = ` "name","hex","rgb" "Red","#FF0000","255,0,0" "Orange","#FFA500","255,165,0" "Yellow","#FFFF00","255,255,0", "Lime","#00FF00","0,255,0" "Blue","#0000FF","0,0,255" "Indigo","#4B0082","75,0,130" `.trim() /// まずは noHeader=true で配列に変換 const arr = csvToArray(csv, true) console.log('arr : ',arr) const obj = csvToArray(csv, false) console.log('obj : ',obj) |
▼ このコードの出力結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
arr : 0: ['Red', '#FF0000', '255,0,0'] 1: ['Orange', '#FFA500', '255,165,0'] 2: ['Yellow', '#FFFF00', '255,255,0,'] ... length: 6 obj : 0: "name": "Red" "hex": "#FF0000" "rgb": "255,0,0" 1: "name": "Orange" "hex": "#FFA500" "rgb": "255,165,0" ... |
ヘッダーカラム名がいらないなら noHeader=true をセット、カラム名も含めたオブジェクトに変換したいなら noHeader=false にすればOKです。
CSVを多用するならライブラリを使う方がいいと思う
CSVは単純なフォーマットです。
ただ次の場合は大人しくライブラリ使ってください
- CSVの読み込みが複数回ある
- 方言ごとの違いを考慮したくない
- そもそも自前実装が嫌い
これは僕の持論ですが……「自前で実装」というと聞こえはいいけど、結局やってることは遠回りにすぎません。他の人が作った優秀なライブラリがあるのに
だから自分自身はできるだけライブラリを使い、できるだけ楽するようにしてます。本当にオリジナリティのある部分にだけ集中するのがグッドですね
以上、JSだけでCSVを配列変換でした。ではまた