F# でパーサーコンビネータを使った CSV ファイルのパース処理 - FParsec 使用
前回(id:fits:20101226)実施したパーサーコンビネータによる CSV ファイルのパース処理を FParsec を使って F# でやってみました。
環境は以下の通り。
- F# 2.0.0
- FParsec 0.8
サンプルのソースは http://github.com/fits/try_samples/tree/master/blog/20101231/
事前準備 - FParsec のビルド
https://bitbucket.org/fparsec/main/downloads/ から FParsec のソースコードをダウンロードした後、適当なディレクトリに解凍しビルドを行います。
ビルド
> cd fparsec\Build\VS10 > msbuild FParsec.fsproj
bin\Debug ディレクトリに作成された FParsec.dll と FParsecCS.dll ファイルをサンプルを作成するディレクトリにコピーしておきます。
CSVファイルのパース
Haskell で書いたサンプルとほぼ同じ実装でよかったので、いきなり以下の CSV ファイルをパースしてみる事にします。
test.csv
1,テスト1,"改行 含み" 2,test2,"カンマ,含み" 3,てすと3,"ダブルクォーテーション""含み"
Haskell の Parsec との違いは以下のような点です。
- try の代わりに attempt を使う
- char の代わりに pchar を使う
- string の代わりに pstring を使う
- return の代わりに preturn を使う
- many の代わりに manyChars を使う
- endBy の代わりに sepEndBy を使う
また、Scala の ~> 等の代わりに以下が使えました。
- ~> の代わりに >>. を使う
- <~ の代わりに .>> を使う
ちなみに、newline は FParsec.CharParsers で定義されているので、自前で定義する必要はありません。
parse_csv.fs
open System open FParsec.Primitives open FParsec.CharParsers let quotedChar = noneOf "\"" <|> attempt (pstring "\"\"" >>. preturn '"') let quotedCell = pchar '"' >>. manyChars quotedChar .>> pchar '"' let cell = quotedCell <|> manyChars (noneOf ",\n") let line = sepBy cell (pchar ',') let csvFile = sepEndBy line newline let cs = Console.In.ReadToEnd() let res = run csvFile cs match res with | Success (v, _, _) -> Console.WriteLine(v) | Failure (msg, _, _) -> Console.WriteLine(msg)
ビルド・実行結果
> fsc /r:FParsec.dll parse_csv.fs > parse_csv.exe < test.csv [[1; テスト1; 改行 含み]; [2; test2; カンマ,含み]; [3; てすと3; ダブルクォーテーション"含み]; ... ]