4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-01-31

背景

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)
4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?