[JavaScript] 正規表現を使ったCSVパーサ
- 2008-01-25
- カテゴリ: Client Side
- タグ: Tips JavaScript RFC CSV パーサ 正規表現
ちょっとした理由から、CSVファイルをJavaScriptで読み込むためのパーサを書きたいと思って、先ほどからがんばってみた。
CSVはいろいろな実装があって正式な仕様がなかなかないらしいけど、考えるのが面倒なのと、Excelが吐くCSVを一応処理できるという理由から、Wikipediaで紹介されていたRFC 4180の形式を採用することに決定。
パーサとかレキサみたいなのは書いたことがないからいびつな仕上がりかも。
仕様
RFC 4180の仕様はだいたい↓のような感じ。
file
は改行(CRLF)で区切られた一つ以上のrecord
で構成されるrecord
はコンマ(,)で区切られた一つ以上のfield
で構成されるfield
にはescaped
、または、non-escaped
の2種類があるescaped
は、ダブルクオート(")で括られた文字列。文字列中のダブルクオートは、二つつなげる("")ことでエスケープする。コンマ・改行も含むことができる。non-escaped
は、コンマ、CR、LF、ダブルクオートを含まない文字列
ダブルクオートで括られた文字列と、括られない文字列との間に型の違いなどはない。大事なのは、ダブルクオートのエスケープが""であるということと、コンマ、CR、LF、ダブルクオートを含む文字列の場合は必ずダブルクオートで括ってエスケープしなければいけないという点っぽい。
バックスラッシュ(\)で文字列中のダブルクオートをエスケープする実装は結構あるっぽいけど、対応するのが面倒なので今回は見送った。
トークン化
まずはCSVをトークン化するレキサを正規表現で作ることにした。
たぶんトークンとして認識する必要があるのは、コンマ、改行、escaped
、non-escaped
の4種類だけだと思う。間違ってるかもだけど。
とりあえず、それぞれを取り出せる正規表現を書いた。
- コンマ
,
- 改行
\r?\n
escaped
[^,"\r\n]+
non-escaped
"(?:[^"]|"")*"
つなげると↓
/,|\r?\n|[^,"\r\n]+|"(?:[^"]|"")*"/g
この正規表現で↓のようなCSVをトークン化してみる。
aaa,"bbb" "c""c","d,d" "e e",,""
↓Firebugで実行してトークン化
>>> 'aaa,"bbb"\r\n"c""c","d,d"\r\n"e\r\ne",,""'.match(/,|\r?\n|[^,"\r\n]+|"(?:[^"]|"")*"/g) ["aaa", ",", ""bbb"", "\r\n", ""c""c"", ",", ""d,d"", "\r\n", ""e\r\ne"", ",", ",", """"]
うまくいってるみたいだ。あとは↓みたいな感じのパーサを書いてトークンを解釈していけばOK。
csv.replace(/,|\r?\n|[^,"\r\n]+|"(?:[^"]|"")*"/g, function(token) { ... })
パーサはまた今度書く。
追記
Tab-Separatedの場合は↓のような正規表現になりそう。
/\t|\r?\n|[^"\t\r\n][^\t\r\n]*|"(?:[^"]|"")*"/g
Excelが吐くテキストを見てると、先頭以外にダブルクオートを含む場合はダブルクオートで括らない仕様らしい。なので、non-escaped
の部分がやや複雑に。
関連記事
トラックバック URL
- http://liosk.blog103.fc2.com/tb.php/74-c1470ecb
トラックバック
- [JavaScript][Perl] 続・正規表現を使ったCSVパーサ
-
正規表現を使ったCSVパーサの続き。
トークン化したCSVを解釈するコードをJavaScriptとPerlで書いた。二つのロジックはほぼ同じ。
それぞれ、第一...
- 2008-01-29
- 発信元: 文系大学的IT系の悲哀