背景
JavaScriptでCSVをパースしてグラフを描いてみたいと思った.ライブラリを使おうかとも思ったけれど, 正規表現でパースしてみたかったので、正規表現の練習も兼ねてやってみた.
前提
FileReaderを使ってCSVファイルを読み込んで, 文字列としてテキストの中身が取得されているとする.
FileReaderのMDNのページはこちら
CSV
少し雑なCSV形式の文字列が読み込まれたと想定する. エクセルで作ったデータをcsvで吐き出して、読み込むとこんな感じになっている.
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次元配列で読み込める.
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をが好き. 大した量のデータでなければ, 転置はこれで十分いける.
const transpose = A=>A[0].map((k,i)=>A.map((v)=>v[i]));
実践
jsnoteに張り付けて, 実践してみた.
手元に用意したエクセルからcsvを吐き出して, importして実行してもいけた.
これでJavaScriptでグラフを描く準備ができた.
// 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)