流行中の

正規表現ベンチ、もしくは文字列生成ベンチ。Python Challenge が一段落したのでやってみる。

ベースライン、速さに定評のある C。

$ gcc -O2 regex.c
$ time ./a.out
no

real    0m0.737s
user    0m0.734s
sys     0m0.003s

なんか遅い。Mac だからか。

意外と古参 Ruby

$ cat regex.rb
query = "b" * (1024 * 1024) + "x";
pat = /^b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b$/;
puts(query =~ pat ? "yes" : "no");
$ 
$ time ruby regex.rb
^Cregex.rb:3:in `=~': Interrupt
    from regex.rb:3


real    60m0.368s
user    59m36.195s
sys     0m4.325s

まさかの長考。

駿足ラクダ O'Caml。

$ cat regex.ml
let query = String.make (1024 * 1024) 'b' ^ "x"
and pat = Str.regexp "^b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b$"
in 
  print_endline (if Str.string_match pat query 0 then "yes" else "no")
$ 
$ ocamlopt str.cmxa regex.ml
$ time ./a.out
^C

real    60m0.476s
user    59m53.573s
sys     0m1.797s

駄目でした。

純真無垢の怠け者 Haskell

$ cat regex.hs
import Text.Regex
query = replicate (1024 * 1024) 'b' ++ "x"
pat = mkRegex "^b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b$"
main = putStrLn $ if matchRegex pat query == Nothing then "no" else "yes"
$ 
$ ghc --make regex.hs 2> /dev/null
$ time ./regex
no

real    0m0.913s
user    0m0.883s
sys     0m0.027s

これは全く怠けていないぞ。

何でも入ってる D 言語。

$ cat regex.d
import std.stdio;
import std.string;
import std.regexp;
void main() {
    auto query = repeat("b", 1024 * 1024) ~ "x";
    auto pat = RegExp("^b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b$");
    writefln(pat.test(query) ? "yes" : "no");
}
$ 
$ gdc regex.d
$ time ./a.out
^C

real    60m0.415s
user    59m37.156s
sys     0m3.480s

たぶん初めて書いた。

探し物、あります grep

$ perl -e 'print ("b" x (1024 * 1024) . "x")' > query
$ time grep -c '^b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b$' query
0

real    0m3.295s
user    0m3.193s
sys     0m0.021s

このくらいが丁度いい速さなんじゃないか。

我らが LiLFeS

$ cat regex.lil
:- module("regex_bench").
query <- pred. query_sub <- pred. pat <- pred. main <- pred.
query(Q) :- query_sub(20, Q1), strcat(Q1, "x", Q).
query_sub(X, Q) :- X <= 0, !, Q = "b".
query_sub(X, Q) :- X1 is X - 1, query_sub(X1, Q1), strcat(Q1, Q1, Q).
pat("^b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b$").
main :- query(Q), pat(P), regex_match(P, Q).
$ 
$ time lilfes -l regex.lil -e "?- main." 2> /dev/null
no

real    0m0.937s
user    0m0.920s
sys     0m0.015s

正規表現が使える時点で何かがすごいと思うのです。

孤独の lysh。

$ cat regex.lsh
:let query := nth 20 (iter (:\x := x :++ x) b) :++ x
:and pat := '^b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b.*b$'
:in 
  regex query pat |> :\x := println :@ ifte (nil? x) no yes
$ 
$ time lysh regex.lsh
no

real    0m0.835s
user    0m0.808s
sys     0m0.019s

なんともコメントしづらい。