Einzelnen Beitrag anzeigen

Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.057 Beiträge
 
Delphi XE2 Professional
 
#29

AW: Schnellstes Entfernen von Chars aus einem String?

  Alt 30. Mär 2015, 02:45
Ich würde folgendes vorschlagen:

Delphi-Quellcode:
function RemoveCharsFromString(const AStr, CharsToRemove: string): string;
var
  i, NewLength: Integer;
begin
  SetLength(Result, AStr);
  NewLength := 0;
  for i := 1 to Length(AStr) do
  begin
    if Pos(CharsToRemove, AStr[i]) = 0 then
    begin
      Result[NewLength] := AStr[i];
      inc(NewLength);
    end;
  end;
  SetLength(Result, NewLength);
end;
Das ist für mich der beste Kompromiss aus Geschwindigkeit, Funktionalität und Einfachheit. Wenn man will, kann man das Pos natürlich auch noch durch eine eigene Schleife ersetzen.

Wenn man unbedingt noch mehr rausholen will:

Zu Sets bzw. Array of Bool[Char] ist zu sagen, dass es wohl schon einen Sinn haben dürfte, weshalb Set auf 256 Elemente begrenzt ist. Mit jedem weiteren Element wächst auch der Speicherverbrauch. Bei WideChar belegt Array of Bool bereits 65 Kilobyte. Würde man statt Bools einzelne Bits verwenden wie bei Set , sind es immer noch 8 Kilobyte. Das ist zu groß um komplett in den CPU-Cache geladen zu werden. Würde man sequenziell durch den Bereich durchlaufen, wäre das zwar kein Problem, aber Sets sind prinzipbedingt Random Access. Würde mich nicht wundern, wenn es schneller wäre, einfach in einer Schleife durch die zu löschenden Elemente zu gehen und immer zu vergleichen (wie in meinem Code), solange es eine überschaubare Anzahl Zeichen ist, die entfernt werden soll.
@Namenloser:
Hast du denn einmal die von dir vorgeschlagene Funktion laufen lassen?

Wenn "JA", dann hättest du merken müssen
1) In der ersten Zeile SetLength(Result, AStr); sollte eine Fehlermeldung kommen, dass man der Länge eines Strings keinen String zuweisen kann.

2) Bei if Pos(CharsToRemove, AStr[i]) = 0 then sollte dir aufgefallen sein, dass du die Position eines Strings innerhalb eines Chars abfragst, was natürlich immer 0 ergibt.

3) Bei
Delphi-Quellcode:
Result[NewLength] := AStr[i];
       inc(NewLength);
sollte es scheppern, weil du Result[0] ein Char zuweisen willst.

Zu
Zitat:
Das ist für mich der beste Kompromiss aus Geschwindigkeit, Funktionalität und Einfachheit.
Die Fragestellung in #1 war
Zitat:
Was ist die SCHNELLSTE Methode, um aus einem String alle Zeichen eines anderen Strings zu entfernen?
Es war also weder ein Kompromiss noch Funktionalität noch Einfachheit gefragt, sondern ausschließlich Schnelligkeit.

Sorry, falls du dich angegriffen fühlen solltest; aber wenn jemand einen Code der gleich 3 so offensichtliche Fehler enthält und so nicht einmal kompilierbar ist, als "Besten Kompromiss" vorstellt, dann juckt es mich schon in den Fingern.

Ich habe, nachdem ich die Fehler in deinem Code korrigiert habe, beide Funktionen laufen lassen, deine aus #28 und meine aus #19.
Als String, aus dem Zeichen entfernt werden sollen, habe ich den letzten Absatz deines Beitrages #28
und als String mit zu entfernenden Zeichen deinen Nick "Namenloser" benutzt.
Die Ergebnisse waren für mich nicht überraschend.

So habe ich getestet;

Delphi-Quellcode:
PROCEDURE TMain.Test;
FUNCTION TimeStamp:Int64;
asm
   rdtsc
   {$IFDEF CPUX64}
   shl rdx,32
   or rax,rdx
   {$ENDIF}
end;
const
   S='Zu Sets bzw. Array of Bool[Char] ist zu sagen, dass es wohl schon einen '+
     'Sinn haben dürfte, weshalb Set auf 256 Elemente begrenzt ist. Mit jedem '+
     'weiteren Element wächst auch der Speicherverbrauch. Bei WideChar belegt '+
     'Array of Bool bereits 65 Kilobyte. Würde man statt Bools einzelne Bits '+
     'verwenden wie bei Set , sind es immer noch 8 Kilobyte. Das ist zu groß '+
     'um komplett in den CPU-Cache geladen zu werden. Würde man sequenziell '+
     'durch den Bereich durchlaufen, wäre das zwar kein Problem, aber Sets '+
     'sind prinzipbedingt Random Access. Würde mich nicht wundern, wenn es '+
     'schneller wäre, einfach in einer Schleife durch die zu löschenden '+
     'Elemente zu gehen und immer zu vergleichen (wie in meinem Code), solange '+
     'es eine überschaubare Anzahl Zeichen ist, die entfernt werden soll.';
   R='Namenloser';
   Res:Array[Boolean] of String=('Ergebnisse verschieden','Ergebnisse gleich');
var
   T0,T1,T2:Int64; S1,S2:String;
begin
   T0:=TimeStamp;
   S1:=RemoveCharsFromString(S,R);
   T1:=TimeStamp;
   S2:=RemoveChars(S,R);
   T2:=TimeStamp;
   Dec(T2,T1);
   Dec(T1,T0);
   ShowMessage(Res[S1=S2]+#13+IntToStr(T1)+#13+IntToStr(T2));
end;
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat