Einzelnen Beitrag anzeigen

nahpets
(Gast)

n/a Beiträge
 
#25

AW: Schneller Stringvergleich nach bestimmtem Muster

  Alt 10. Dez 2015, 12:29
Mal ein paar (unsinnige?) Gedankenspiele:

Ab ins alte Turbopascal, dort enthielt bei Strings das 0. Byte die Länge.
Das dürfte heute bei ShortString noch so sein. Geht ShortString auch? Wenn ja:
Delphi-Quellcode:
var sBaseStr : ShortString;
    lBaseStr : Byte absolut sBaseStr;
Damit befindet sich die Längenangabe von sBaseStr automatisch in lBaseStr. Die wiederholte Längenabfrage per Length kann damit entfallen.

Alternativ die Länge nur einmalig abfragen und in Variabeln speichern. Alles entfernen, was wiederholt gemacht werden muss. Lieber ein paar zusätzliche Variabeln "mitschleppen".
Delphi-Quellcode:
function MatchRule(const BaseStr: String; const CompareList: TStringList): Boolean;
var
  i : Integer;
  j : Integer;
  cntForward : Integer;
  cntBackward : Integer;
  lBase : Integer;
  lComp : Integer;
  StrBase : String;
  lStrBase : Integer; // Länge von StrBase
  StrCompare : String;
  lStrCompare : Integer; // Länge von StrCompare
  lStrBaseStrCompare : Integer; // Differenz: lStrCompare - lStrBase
begin
  Result := False;
  bBreak := False;
  lBase := Length(BaseStr);
  for i := 0 to CompareList.Count - 1 do begin
    lComp := Length(CompareList[i]);
    if InRange(lBase - lComp,-1,1) then begin
      cntForward := 0;
      cntBackward := 0;
      if lBase <= lComp then begin
        StrBase := BaseStr;
        StrCompare := CompareList[i];
      end else begin
        StrBase := CompareList[i];
        StrCompare := BaseStr;
      end;
      // compare contains base
      lStrBase := Length(StrBase);
      lStrCompare := Length(StrCompare);
      if lStrBase < lStrCompare then Result:= Pos(StrBase, StrCompare) > 0;
      if not Result then begin
        // check forward
        for j := 1 to lStrBase - 1 do begin // Warum kein Vergleich beim letzten Zeichen?
          if StrBase[j] = StrCompare[j] then inc(cntForward)
          else break; // Beim ersten Unterschied raus aus For...
        end;
        // check backward
        lStrBaseStrCompare := lStrCompare - lStrBase;
        for j := lStrBase downto 1 do begin
          if StrBase[j] = StrCompare[j + lStrBaseStrCompare] then
            inc(cntBackward)
          else break; // Beim ersten Unterschied raus aus For...
        end;
        if lBase = lComp then
          // bei gleicher Länge darf es einen Unterschied geben.
          Result := (cntForward + cntBackward) >= (lStrBase - 1)
        else
          Result := (cntForward + cntBackward) = lStrBase;
      end;
      if Result then Exit; // hier raus, wenn Result = True;
    end;
    // else Continue; // überflüssig, da wir hier ja sowieso am Ende der Schleife sind.
  end;
end;
Ob das jetzt große Geschwindigkeitsunterschiede gibt, mag ich nicht zu beurteilen.
Meine praktische Erfahrung ist jedoch, dass bei häufig wiederholten Routinen durchaus Geschwindigkeitsvorteile zu erwarten sind, wenn man wiederholt per Pos, Length... ermittelte Werte in separaten Variablen "mitschleppt", um die wiederholte Ausführung, eigentlich trivialer Funktionen, zu eliminieren.
  Mit Zitat antworten Zitat