#Python のパーサコンビネータライブラリとして、parsyとpyparsingというのを見つけたので試してみたが、結構遅い。
Pythonでちょっとしたパーサを書きたいときとかみんなどうしてるのだろう……?
あるデータセットのファイルを全て読み込んでパースする時間を測った結果が以下。
参考までに #Haskell のパーサコンビネータライブラリのmegaparsec/attoparsecを使った場合の時間も含めてみる。
parsy-1.1.0:
https://github.com/python-parsy/parsy
real 290m7.032s
user 289m25.980s
sys 0m9.404s
pyparsing-2.2.0:
http://pyparsing.wikispaces.com/
real 562m41.623s
user 561m48.652s
sys 0m16.292s
megaparsec-5.3.1:
http://hackage.haskell.org/package/megaparsec
real 18m12.025s
user 17m26.104s
sys 0m26.456s
attoparsec-0.13.1.0:
http://hackage.haskell.org/package/attoparsec
real 15m46.415s
user 14m31.964s
sys 0m59.652s
ただし、parsy/pyparsingでは(bytesではなく)strを使ったのに対して、megaparsec/attoparsecでは(Textではなく)ByteStringを使っているので、その点ではフェアではない比較になってしまっている。
あと、megaparsecが意外と速くて驚いた。 attoparsecの倍くらい遅いイメージだったけれど、ByteStringを使う場合にはそこまで性能差ないんだなぁ。
それから、Haskellのparsecを使っていた自分からすると、parsyの方がpyparsingよりも分かりやすく、またpyparsingは空白の扱いがどうなっているのかとかちょっと不安になるけれど、たぶんpyparsingの方がPython的ではあるんだろうな。
csvには変換しにくいデータなので、pandasでは難しそうですが、jsonにしておくのは手ですね。 今は、パース済みのものをpickleでダンプして使ったりも試してはいました。
real 79m45.315s
user 78m10.016s
sys 0m13.092s
他のコードと違って、lexerをparserから分離したので、その影響も大きいかも。