Einzelnen Beitrag anzeigen

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
 
#13

AW: TPerlRegEx - stack overflow

  Alt 13. Jun 2012, 17: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 17:49 Uhr)
  Mit Zitat antworten Zitat