regexpの代わりにparser
Erlangで正規表現がイマイチ使えないので,パーサを書く方法を試してみた.
HaskellのParsecのようなライブラリ parser.erl を使ってみた.
実行回数を1桁増やして,0xffff回実行にして,再度PerlとErlangで比較.
Perlの正規表現最強.
まぁ,言語自体にCで最適化されているエンジンが搭載されているのと比較するのがアレなのかもしれないけど. それにしても,もう少し速い方法があるといいんだけども...
nativeコンパイルでだいぶ速くなるのが救いかな?
oregexpを使うとかPCREを外部で呼び出すとかしても,ドライバのオーバーヘッドが大きそうだから,iconvで同一回数回したときの0.6秒よりは小さくならなさそうだし,互角なレベルに持って行くのは厳しそう.
言語レベルで内部構造べったりな感じで拡張する方法があれば良いけど,マニュアルを見る限りはなさそうだし.(互換性のためにあえてそういう仕様にしているぽい感じ)
とりあえず,正規表現を使うのに比べて10倍以上は速くなっているから,こんなもんかなぁ.
ソースコードは以下の通り.(適当なところで改行いれてあります)
HaskellのParsecのようなライブラリ parser.erl を使ってみた.
実行回数を1桁増やして,0xffff回実行にして,再度PerlとErlangで比較.
| 方法 | 言語 | 時間(sec) |
|---|---|---|
| parser | Erlang (beam) | 2.843180 |
| Erlang (native) | 1.079725 | |
| Erlang (beam+smp) | 3.035176 | |
| Erlang (native+smp) | 0.776946 | |
| 正規表現 | Perl | 0.197326 |
Perlの正規表現最強.
まぁ,言語自体にCで最適化されているエンジンが搭載されているのと比較するのがアレなのかもしれないけど. それにしても,もう少し速い方法があるといいんだけども...
nativeコンパイルでだいぶ速くなるのが救いかな?
oregexpを使うとかPCREを外部で呼び出すとかしても,ドライバのオーバーヘッドが大きそうだから,iconvで同一回数回したときの0.6秒よりは小さくならなさそうだし,互角なレベルに持って行くのは厳しそう.
言語レベルで内部構造べったりな感じで拡張する方法があれば良いけど,マニュアルを見る限りはなさそうだし.(互換性のためにあえてそういう仕様にしているぽい感じ)
とりあえず,正規表現を使うのに比べて10倍以上は速くなっているから,こんなもんかなぁ.
ソースコードは以下の通り.(適当なところで改行いれてあります)
-module(strparser).
-export([bench/0, bench/1]).
bench() ->
Time = timer:tc(strparser, bench, [16#ffff]),
io:format("~w~n", [Time]).
bench(0) ->
0;
bench(N) ->
String = "12.34.123.12 - - [17/Apr/2007:23:53:13 +0900] \"
GET /html/1234.html HTTP/1.1\" 200 6980 \"http://www.
mikage.to/html/1234.html\" \"Mozilla/4.0 (compatible; MS
IE 6.0; Windows NT 5.1; SV1)\"\n",
{Str1, Str2} = parser:parse(parser:pAnd([
parser:pMany1(parser:pSat(fun (C1) ->
not lists:member(C1, " ") end)),
fun parser:pSpace/1,
parser:pMany1(parser:pSat(fun (C1) ->
not lists:member(C1, " ") end)),
fun parser:pSpace/1,
parser:pMany1(parser:pSat(fun (C1) ->
not lists:member(C1, " ") end)),
fun parser:pSpace/1,
parser:pChar($[),
parser:pMany1(parser:pSat(fun (C1) ->
not lists:member(C1, "]") end)),
parser:pChar($]),
fun parser:pSpace/1,
parser:pChar($")
]), String),
{Str3, Str4} = parser:parse(parser:pAnd([
parser:pMany1(parser:pSat(fun (C1) ->
not lists:member(C1, "\"") end))
]), Str2),
% io:format("~s~n", [Str3]),
bench(N - 1).
Comments