JavaScriptでCSV形式の文字列を正規表現でパースして2次元配列に入れる方法

## 背景
JavaScriptでCSVをパースしてグラフを描いてみたいと思った.ライブラリを使おうかとも思ったけれど, 正規表現でパースしてみたかったので、正規表現の練習も兼ねてやってみた.

## 前提
FileReaderを使ってCSVファイルを読み込んで, 文字列としてテキストの中身が取得されているとする.  
FileReaderのMDNのページは[こちら](https://developer.mozilla.org/ja/docs/Web/API/FileReader)

## CSV
少し雑なCSV形式の文字列が読み込まれたと想定する. エクセルで作ったデータをcsvで吐き出して、読み込むとこんな感じになっている.

``` javascript
const sample =
  " 'title', 'tmp1', 'tmp2'\r\n \
          1,      1,     1 \r\n \
                           \r\n \
           ,       ,       \r\n \
          3,      4,     5 \r\n \
          5,      5,     5 \r\n \
          2,      3,     4 \r\n";
```

## 正規表現
split, map, filterとか使って, csvをパースするための関数はこんな風になった.

step1: 改行コード(\n, \r, \n\r)でスプリットして, 配列に入れる.
step2: 空白だけの行, タブだけの行, カンマだけの行を取り除く.
step3: 各行で先頭と末尾の空白を取り除く.
step4: 各行でカンマの後に続く空白を取り除く.
step5: 各行でカンマでスプリットして配列に入れる.
step6: 各行でスプリットして配列に入れた値が数値の場合は, 文字から数値に変換する.  
これで2次元配列で読み込める. 

``` js
const csvParse = csv => csv
  .split(/\r\n|\n|\r/) //split by line feed codes
  .filter((k)=>k.match(/[^,\s]/)) //remove empty lines
  .map((k)=>k.trim() //remove white spaces of begining and end of line
    .replace(/,\s+/g,",") //remove white spaces
    .split(",") //split by cannma
    .map((l)=>isNaN(l)? l:parseFloat(l)) //convert string to flot
  ); 
```

## 転置
csvParseでパースしたままだと, 各行ごとに配列に収められているのでグラフを描く時に不便. データは列毎に並べて,一番上の行はインデックスになっていることが多い.
そこで, 転置しないといけない. for文でpushする方が速いと思うけれど, 一行で書けるmapをが好き. 大した量のデータでなければ, 転置はこれで十分いける.

``` js
 const transpose = A=>A[0].map((k,i)=>A.map((v)=>v[i]));
```

## 実践
[jsnote](https://toyoharu-nishikawa.github.io/jsnote/#sample=sample/JavaScript/parse_csv.js)に張り付けて, 実践してみた.
手元に用意したエクセルからcsvを吐き出して, importして実行してもいけた.
これでJavaScriptでグラフを描く準備ができた.

```` js
// read csv file in jsnote
// step1: push the button of import and select csv file
// step2: push the button of run or press the keys of "Shifit + Enter"

const transpose = A=>A[0].map((k,i)=>A.map((v)=>v[i]));
const csvParse = csv => csv
  .split(/\r\n|\n|\r/) //split by line feed codes
  .filter((k)=>k.match(/[^,\s]/)) //remove empty lines
  .map((k)=>k.trim() //remove white spaces of begining and end of line
    .replace(/,\s+/g,",") //remove white spaces
    .split(",") //split by cannma
    .map((l)=>isNaN(l)? l:parseFloat(l)) //convert string to flot
  ); 
  
const sample = 
  " 'title', 'tmp1', 'tmp2'\r\n \
          1,      1,     1 \r\n \
                           \r\n \
           ,       ,       \r\n \
          3,      4,     5 \r\n \
          5,      5,     5 \r\n \
          2,      3,     4 \r\n";

const csv = importTexts.length >0 ? importTexts[0].text : sample; //assign imported text or sample string to csv
console.log(csv);

const data = csvParse(csv);
console.log(data);

const index = data.shift(); //comment out tow lines from here
console.log(index);         //if index is not inclueded in csv

const dataT = transpose(data);
console.log(dataT);
```

## 参考
- [jsnote](https://toyoharu-nishikawa.github.io/jsnote/)はgithubのページでオンラインで使える.  
https://toyoharu-nishikawa.github.io/jsnote/
- [Docker Hub](https://hub.docker.com/r/toyohal24/jsnote/)からpullしても使える.  
https://hub.docker.com/r/toyohal24/jsnote/
- Git Hubのリポジトリからmasterをクローンしても使える[こちら](https://github.com/Toyoharu-Nishikawa/jsnote)