AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

TPerlRegEx - stack overflow

Ein Thema von liftoff · begonnen am 12. Jun 2012 · letzter Beitrag vom 14. Jun 2012
Antwort Antwort
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#1

AW: TPerlRegEx - stack overflow

  Alt 12. Jun 2012, 21:13
Willkommen in der DP

Ich kenne mich mit dem Wrapper und PCRE-Interna nicht aus, aber könnte es daran liegen, dass Unicode-Strings doppelt so viele Bytes pro Zeichen haben wie Ansi-Strings und daher doppelt so viel Platz auf dem Stack benötigt wird?

Die Größe des Stack kann man bei Delphi in den Projekt-Optionen unter Linker einstellen (jedenfalls bei Delphi 2006, bei XE ist der Build-Prozess ja etwas anders).

Oder könnte es sein, dass der neue Wrapper standardmäßig non-greedy statt greedy (oder umgekert?) matcht? Ich sehe zwar auf den ersten Blick nicht, wo das bei diesem Ausdruck einen Unterschied machen sollte, aber wie gesagt kenne ich mich mit den PCRE-Interna nicht aus. Vielleicht einfach mal ausprobieren...

Geändert von Namenloser (12. Jun 2012 um 21:18 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.378 Beiträge
 
Delphi 12 Athens
 
#2

AW: TPerlRegEx - stack overflow

  Alt 12. Jun 2012, 21:31
PCRE gibt es nur für ANSI. (Unicode wird als UTF-8 behandelt).

Es wird hier das originale PCRE von Philip Hazel als *.obj ins Delphi gelinkt. (unter Mac über eine DLL)
Also genau das Selbe, was man in C#, PHP und Co. finden kann.

In Delphi wird daher das Unicode in UTF-8 umgewandelt, also nix mit 2 Byte pro Char,
aber ansonsten ist da nix Besonderes dran. Nur Unicode-UTF8-Konvertierungen und alles in eine Klasse verpackt, aber am Ende nur der originale C++-Code.


Welche Delphi-Edition nutzt du denn genau?
Falls nicht grade die "Starter", dann aktiviere in den Prokjektoptionen mal die DebugDCUs.

Wie sieht der Stacktrace aus?
Und knallt es genau?

Ein Testprojekt hast du nicht zufällig für uns?
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu (12. Jun 2012 um 21:33 Uhr)
  Mit Zitat antworten Zitat
liftoff

Registriert seit: 6. Jun 2012
Ort: Frankfurt am Main
11 Beiträge
 
Delphi XE Enterprise
 
#3

AW: TPerlRegEx - stack overflow

  Alt 12. Jun 2012, 22:19
Bin gerade nicht im Büro . Auf jeden Fall ist es keine Starter Edition.

Ich habe mir einen Wrapper für den Wrapper geschrieben, damit ich die Orginalsourcen meiner Bibliothek (etwa 15000 Codezeilen) nicht anfassen muss. Diese arbeitet weiterhin mit string, der ja UTF16-codiert ist. Problem war nur die Umwandlung der Matchpositionen von UTF8 nach UTF16. Ein €-Zeichen hat beispielsweise 3 Byte in UTF8 und ein Char (2Byte) in UTF16. Das läuft auch alles prima, solange die zu matchenden Nachrichten nicht zu lang werden.

Mein Problem kann man auch ganz einfach mit der originalen TPerlRegEx nachstellen, also losgelöst von meinem Code.
Es knallt dann direkt beim Aufruf von pcre_exec in TPerlRegEx.Match.
Geliefert wird ein EStackOverflow.

({4:\r\n(?:[^\r\n]*\r\n)*-})

Der Teilausdruck in der Mitte muss ja von pcre_exec intern immer wieder pro Zeile durchgeackert werden. Und irgendwo bei 300 Zeilen (genaue Zahl habe ich jetzt nicht da) ist dann einfach Schluss und die Exception wird ausgeworfen. In meinem Delphi-2007-Wrapper um pcre.obj ist das nicht der Fall.

Entweder ich muss den Ausdruck anfassen, was dann bedeutet, dass ich unter Umständen eine Menge solcher Gefahrenstellen in der Bibliothek habe.
Oder es gelingt irgendwie, die Stackgröße zu erhöhen. Auf pcre.org wird das Thema zwar durchgekaut, allerdings gelingt es mir bisher nicht, dass mit Delphi zu verheiraten.

Wie soll so ein Beispielprojekt aussehen? Könnte ich dann morgen sicherlich noch liefern.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.652 Beiträge
 
Delphi 12 Athens
 
#4

AW: TPerlRegEx - stack overflow

  Alt 12. Jun 2012, 22:41
Ich kann mich erinnern, daß wir vor Jahren mal ein ähnliches Problem mit TPerlRegEx hatten, das mangels Pascal-Sourcen weder zu debuggen, noch zu beheben war. Die (zumindest damalige) Implementation der RegEx-Enhine war stark rekursiv und brachte bei bestimmten Eingabedateien einen StackOverflow.

Die damalige Lösung bestand darin, auf TPerlRegEx zu verzichten und einen nicht-rekursiven, handgeschriebenen Parser zu verwenden. War auch um Klassen performanter und ließ sich wesentlich besser debuggen.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
liftoff

Registriert seit: 6. Jun 2012
Ort: Frankfurt am Main
11 Beiträge
 
Delphi XE Enterprise
 
#5

AW: TPerlRegEx - stack overflow

  Alt 13. Jun 2012, 10:36
Vielen Dank für die bisherigen Anworten.

Einen eigenen Parser zu schreiben, wäre hier viel zu aufwändig. Das Ganze ist ja bereits ein Parser für Swiftnachrichten auf der Basis von regulären Ausdrücken. In der Tat ist TPerlRegEx ungefähr halb so schnell, wie mein alter Wrapper. Insgesamt ist die Performance aber zufriedenstellend.

Hier dann mal ein Beispielcode:
Code:
var re : TPerlRegEx;
    teststr : UTF8String;
    l1 : integer;
begin
  try
    re := TPerlRegEx.create;
    re.Options := [precaseless];
    re.State := [];

    re.RegEx := '({4:\r\n(?:[^\r\n]*\r\n)*-})';
    re.Compile;

    //    Nun Beispielstring mit Inhalt
    //    {4:
    //    :00X:ABCDEFB0123456789
    //    :00X:ABCDEFB0123456789
    //    :00X:ABCDEFB0123456789
    //    :00X:ABCDEFB0123456789
    //    ...
    //    -}
    //    zusammenbauen

    TestStr := '{4:'+chr(13)+chr(10);

    for l1 := 1 to 500 do
        TestStr := TestStr + ':00X:ABCDEFB0123456789' +chr(13)+chr(10);

    TestStr := TestStr + '-}';


    re.Subject := TestStr;

    re.Match;

    { TODO -oUser -cConsole Main : Code hier einfügen }
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;

  ReadLn;
end.
Es knallt bei re.match.

Angehängt ist auch ein Beipielprojekt. Ist hoffentlich so korrekt. Delphi XE ist übrigens die Enterprise-Edition.

TRegExErr.zip
  Mit Zitat antworten Zitat
ele

Registriert seit: 18. Feb 2009
129 Beiträge
 
Delphi 2010 Professional
 
#6

AW: TPerlRegEx - stack overflow

  Alt 13. Jun 2012, 10:52
Huch, bin etwas überrascht hier noch einen Delphi Programmierer anzutreffen der sich mit SWIFT-Messages herumschlagen muss. Wilkommen im Club

Folgende RegEx funktioniert:

Code:
({4:\r\n(?:[^\r\n]*\r\n)*?-})
P.S: Falls du jemals mit deinem Job unzufrieden wirst. Unsere Firma sucht immer wieder mal Delphi-Programmiere mit SWIFT-Erfahrung. Melde dich einfach per PM bei mir falls du interessiert bist.
  Mit Zitat antworten Zitat
WladiD

Registriert seit: 27. Jan 2006
Ort: Celle
145 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: TPerlRegEx - stack overflow

  Alt 13. Jun 2012, 11:43
Folgende RegEx funktioniert:

Code:
({4:\r\n(?:[^\r\n]*\r\n)*?-})
Ich habe keine Ahnung von SWIFT (zumindest nicht im Detail), aber der reguläre Ausdruck ist definitv nicht richtig.

- Geschweifte Klammern haben in pcre eine spezielle Bedeutung (Quantifizierung) und müssen daher escaped werden, wenn man sie matchen möchte
- Das Fragezeichen vor der Klammer ist auch fragwürdig, denn es ist ein Quantifizierer also ein Kürzel für {0,1} und ein vorhergehendes Char, Set oder Gruppe fehlt demnach

Dieser Ausdruck würde die vorliegenden Daten richtig matchen:

Code:
(\{4:\r\n(:\w{3}:.*\r\n)*-\})
PS: Reguläre Ausdrücke sind (richtig angewendet) in 99% aller Fälle schneller (weil sie direkt in Maschinencode übersetzt werden) als ein selbstgeschriebener Parser, eine bestimmte Komplexität an den zu matchenden Daten vorausgesetzt.
Waldemar Derr
Profil bei GitHub
  Mit Zitat antworten Zitat
Benutzerbild von MaBuSE
MaBuSE

Registriert seit: 23. Sep 2002
Ort: Frankfurt am Main (in der Nähe)
1.840 Beiträge
 
Delphi 10 Seattle Enterprise
 
#8

AW: TPerlRegEx - stack overflow

  Alt 13. Jun 2012, 16:18
Code:
...
    re.RegEx := '({4:\r\n(?:[^\r\n]*\r\n)*-})';
Hallo,
ich habe mit meinen RegEx Experten gesprochen.

Er sagt, Deine RegEx sieht so aus, als hättest Du den Unterschied zwischen greedy und non-greedy nicht richtig verstanden, als Du diese Expression erstellt hast. Es sieht so aus, als wolltest Du das non-greedy manuell erzwingen. Das macht die RegEx nur unnötig kompliziert.

Folgende Expression würde alles zwischen dem '{4:' und '-}' auswählen. Mit der non-greedy Option '?' die nach dem Wildcard '*' steht, wird das Ergebnis möglichst kurz gehalten.
Code:
...
    re.RegEx := '(\{4\:.*?-\})';
...
'{4: bla bla bla bla -}{4: bla bla -}'

-> '{4: bla bla bla bla -}' wird ausgewählt


Code:
...
    re.RegEx := '(\{4\:.*-\})'; // ohne ? -> greedy
...

ohne ? -> greedy wird folgendes ausgewählt:

'{4: bla bla bla bla -}{4: bla bla -}'

Durch die Vereinfachung der RegEx ist es nicht nur einfacher zu lesen sondern es werden auch weniger rekursive Aufrufe nötig, also auch der Stack weniger beansprucht
Ich hoffe das hilft Dir weiter.

cu
MaBuSE

[edit]
Obiges Beispiel funktioniert natürlich nur wenn die SingleLine Option aktiv ist. Nur dann steht der '.' auch für ein '/n'.

Delphi-Quellcode:
...
// re.Options := [preCaseLess, preSingleLine];
// re.RegEx := '(\{4\:.*?-\})';

    // alternativ kann man die Optionen auch in die RegEx schreiben:
    // '?' -> jetzt kommen Optionen -> 's' = SingleLine ; 'i' = CaseLess -> ':' = Optionen Ende
    re.Options := [];
    re.RegEx := '(?si:\{4\:.*?-\})';
...
Habe ich ausprobiert funktioniert.
[/edit]

[edit] Beispiel:
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

uses
  RegularExpressionsCore;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var re : TPerlRegEx;
    teststr : UTF8String;
    l1 : integer;
begin
  try
    re := TPerlRegEx.create;
    re.State := [];
    re.Options := [];
    re.RegEx := '(?si:\{4\:.*?-\})';
    re.Compile;

    // Nun Beispielstring mit Inhalt
    // {4:
    // :00X:ABCDEFB0123456789
    // :00X:ABCDEFB0123456789
    // -}
    // ...
    // {4:
    // :00X:ABCDEFB0123456789
    // :00X:ABCDEFB0123456789
    // -}
    // zusammenbauen

    TestStr := '{4:'+chr(13)+chr(10);
    for l1 := 1 to 2 do
    begin
      TestStr := TestStr + ':00X:ABCDEFB0123456789' +chr(13)+chr(10);
    end;
    TestStr := TestStr + '-}';
    TestStr := TestStr + TestStr + TestStr + TestStr;

    re.Subject := TestStr;

    if re.Match then
    begin
      Memo1.Lines.Add(re.MatchedText);
      Memo1.Lines.Add('-------------------');

      while re.MatchAgain do
      begin
        Memo1.Lines.Add(re.MatchedText);
        Memo1.Lines.Add('-------------------');
      end;
    end
    else
    begin
      Memo1.Lines.Add('Kein Treffer')
    end;

  except
    on E: Exception do
      Memo1.Lines.Add(E.ClassName+ ': '+ E.Message);
  end;
end;

end.
[/edit]
(°¿°) MaBuSE - proud to be a DP member
(°¿°) MaBuSE - proud to be a "Rüsselmops" ;-)

Geändert von MaBuSE (13. Jun 2012 um 16:49 Uhr)
  Mit Zitat antworten Zitat
liftoff

Registriert seit: 6. Jun 2012
Ort: Frankfurt am Main
11 Beiträge
 
Delphi XE Enterprise
 
#9

AW: TPerlRegEx - stack overflow

  Alt 13. Jun 2012, 17:19
Wow. Danke fur die ausführliche Untersuchung.
Ich möchte, dass sich das nur matcht, wenn die unter #11 beschriebenen Kriterien zutreffen.
Also nach {4: ein Umbruch, danach Zeilen mit Egal plus Umbruch und danach eine letzte Zeile mit einem -} am Anfang.

So ganz habe ich aber in der Tat den Zusammenhang mit dem Stack noch nicht ergründen können.
  Mit Zitat antworten Zitat
Antwort Antwort

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:00 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz