Der speed vergleich hinkt allerdings auch ein bisschen, du erstellst in jeder iteration ein TRegExpr und freest es wieder. Create und Free sind, da sie den Memory Manager involvieren grundsätzlich schonmal ziemlich langsam. Gleichzeitig benutzt du immer den gleichen Regex, weshalb es keinen sinn macht immer neu zu erzeugen. Da anscheinend TRegExpr keinen Automaten baut, ist das nicht so tragisch, aber z.B. Python hatte das problem das wenn man einen regex immer wieder gebaut hat das bauen des NFAs ziemlich lange im vergleich zum matchen gedauert hat. Seit Python 2.5 oder so werden daher regex auch gecached damit der overhead nicht immer wieder erzeugt wird.
In C++ gibt es z.B. sogar bestrebungen das bauen der Automaten in die Compiletime zu verlagern, sodass zur laufzeit nur das DFA matching stattfinden muss. Das ist dann richtig schnell.
Um mal kurz den vergleich zu geben zwischen einem DFA und nicht DFA matching, habe ich mal das folgende programm genommen:
Code: Alles auswählen
program Project1;
{$mode objfpc}{$H+}
uses
SysUtils, classes, uregexpr;
var
expr: TRegExpr;
sl: TStringList;
s: String;
begin
expr := TRegExpr.Create('(\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}');
sl := TStringList.Create;
try
sl.LoadFromFile(ParamStr(0));
if expr.Exec(sl.Text) then
repeat
s := expr.Match[0];
WriteLn(s);
until not expr.ExecNext;
finally
sl.Free;
expr.Free;
end;
ReadLn;
end.
Und gegen grep (das den regex zu nem DFA kompiliert) auf einem etwas größeren Server log (500mb) antreten lassen um alle ip addressen zu matchen:
Code: Alles auswählen
$> time grep -Eo '(\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}' nextcloud_access_log > /dev/null
grep --color=auto --exclude-dir={.bzr,CVS,.git,.hg,.svn,.idea,.tox} -Eo > 0.00s user 0.00s system 17% cpu 0.009 total
$> time ./match nextcloud_access_log > /dev/null
./match nextcloud_access_log > /dev/null 49.10s user 0.84s system 98% cpu 50.552 total
Der echte DFA ohne backtracking ist etwa einen faktor 10000 schneller.
Lustigerweise bedeutet das auch das der wohl schnellste weg große strings zu durchsuchen mit dem FPC vermutlich ist grep über TProcess aufzurufen und dessen output zu parsen.