ちょっと前にjavascriptで構文解析とかがはやった気がするので、javascriptのリハビリがてらかいてみた。
ググってみると
あたりがあるのだが、まぁ勉強ということで。javascriptらしく書いてみようかと。
ということで、モナドがどーたらとか難しい話はまぁおいておいて、簡単に値がとりだせますよ、という見栄え重視で作ってみた。基本的な機能しかない。けど拡張するのは簡単。せめて相互再帰くらいは実装したほうがよかったかな。まぁ、こんなの真剣に使う人もいないと思うので、要望があればってことで。ちなみに依存するライブラリはありません。
ダウンロード : Inforno.Parsec
たとえばこんな感じにCSVのパーサが定義できる。withを使ってDSLっぽくしてみた。
1var CSVParser = Inforno.Parsec.Parsers.define(function(){with(this){
2 this.chars = chrLike(function(c){ return c != '' && c!=',' && c!='\n' && c!='"';});
3 this.quote = chr('"')
4 this.quoteInQuote = str('""') .ret(function(){return '"';});
5 this.charInQuote = chrLike(function(c){ return c!='"';});
6 this.quotedField = quote .and (rep((quoteInQuote) .or (charInQuote))) .and (quote)
7 .ret(function(q1, cs, q2){
8 return cs.join("");
9 });
10 this.field = rep1(chars) .ret(Return.str)
11 this.record = sep( (field) .or (quotedField), chr(","), true) .ret(function(fields) {
12 return {fields: fields};
13 })
14 this.csv = sep(record, chr("\n"), true) .and(eof) .ret(function(records) {
15 return {records : records};
16 })
17}});
18
19var testCsv = [
20'"aaa","b',
21'bb","ccc",zzz,"y""Y""y",xxx'
22].join("\n");
23
24var parser = new CSVParser(testCsv);
25var parseResult = parser.csv.parse()
26if(parseResult.success()) {
27 var records = parseResult.result[0].records;
28 for(var i=0,l=records.length;i<l;i++){
29 alert("row("+i+") "+records[i].fields);
30 }
31}
実はパーサコンビネータって簡単にかけるんだけど、世間的にちゃんと認識されているのかなあ。思うに、パーサコンビネータといえばHaskell界隈であり 、関数型界隈であり(もちろんちゃんとJAVAとかの実装もあるんだけど)、モナドでありそういうところって専門用語が多いから「ふつうの」プログラマからは簡単に見えてないような気がするなあ。