Entwickler-Ecke

Algorithmen, Optimierung und Assembler - Explode-Funktion optimieren


n-regen - So 28.02.10 19:30
Titel: Explode-Funktion optimieren
Hallo!

Ich habe mir gerade eine Funktion gebastelt, die einen String anhand eines Trennzeichens in drei Teile zerlegt, eventuelle Anführungszeichen an Anfang und Ende der Teilstrings entfernt und diese dann als record zurückgibt.
Kann man die Funktion noch irgendwie schneller machen?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
type
  TExplodedString = record
    value1:string;
    value2:string;
    value3:string;
  end;

function explode(inputstr, separator: string):TExplodedString;
var ps,dest: integer;
begin
  dest := 0;
  result.value1 := '';
  result.value2 := '';
  result.value3 := '';
  for ps := 1 to length(inputstr) do begin
    if inputstr[ps] = separator
    then inc(dest)
    else begin
      case dest of
        0: result.value1 := result.value1 + inputstr[ps];
        1: result.value2 := result.value2 + inputstr[ps];
        2: result.value3 := result.value3 + inputstr[ps];
      end;
    end;
  end;
  if result.value1[1] = '"'
  then begin
    result.value1 := copy(result.value1, 2, length(result.value1)-2);
    result.value2 := copy(result.value2, 2, length(result.value2)-2);
    result.value3 := copy(result.value3, 2, length(result.value3)-2);
  end;
end;


F34r0fTh3D4rk - So 28.02.10 19:43

Ungetestet, aber so oder so ähnlich könnte es gehen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
type
  TExplodedString = array[0..2of string;

function explode(inputstr, separator: string):TExplodedString;
var
  i, p: integer;
  exstr: string;
begin
  for i := 0 to 2 do
  begin
    p := pos(inpustr, separator);
    exstr[i] := copy(inputstr, 1, p-1);
    inputstr := copy(inputstr, p+length(separator));
  end;
  return exstr;
end;

Gibt es sowas wie NextPos() in Delphi?


jaenicke - So 28.02.10 19:48

user profile iconF34r0fTh3D4rk hat folgendes geschrieben Zum zitierten Posting springen:
Gibt es sowas wie NextPos() in Delphi?
Meinst du Suche in der Delphi-Reference POSEX?


F34r0fTh3D4rk - So 28.02.10 19:51

Delphi scheint leider nicht so eine tolle API zu haben wie Java*, deshalb hab ichs auf die Schnelle nicht gefunden ;)

Dann ist es ungefähr so (ungetestet):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
function explode(inputstr, separator: string):TExplodedString;
var
  i, p, last: integer;
  exstr: TExplodedString;
begin
  last = 1;
  for i := 0 to 2 do
  begin
    p := posex(inpustr, separator, last);
    exstr[i] := copy(inputstr, 1, p-1);
    last := p+length(separator); 
  end;
  result := exstr;
end;

*String [http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html], ja OOP ist schon was feines ;)

EDIT: return durch result := ersetzt.


BenBE - So 28.02.10 19:59

Wenn zuwenige Trennzeichen enthalten ist, gibt Copy nen Leerstring zurück für den letzten Teilstring


n-regen - So 28.02.10 21:02

So, ich habe user profile iconF34r0fTh3D4rks Vorschlag von halb-C nach Delphi übersetzt und überarbeitet:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
function TForm1.explode(inputstr, separator: string):TExplodedString;
var
  i, p, last: integer;
begin
  last := 1;
  for i := 0 to 1 do
  begin
    p := posex(separator, inputstr, last);
    result[i] := copy(inputstr, last, p-last);
    last := p+length(separator);
  end;
  result[2] := copy(inputstr, last, length(inputstr)-(last-1));
  if result[0][1] = '"' then begin
    result[0] := copy(result[0], 2, length(result[0])-2);
    result[1] := copy(result[1], 2, length(result[1])-2);
    result[2] := copy(result[2], 2, length(result[2])-2);
  end;
end;

Die Funktion ist zwar immer noch (oder schon wieder) ziemlich langsam, aber sie funktioniert.
Vielen Dank euch allen!


F34r0fTh3D4rk - So 28.02.10 21:08

Sry wegen der fremdartigen Syntax :lol: , aber ich benutze seit Jahren kein Delphi mehr ;)

Eine Frage: Wozu ist das?

Delphi-Quelltext
1:
2:
3:
4:
5:
  if result[0][1] = '"' then begin
    result[0] := copy(result[0], 2, length(result[0])-2);
    result[1] := copy(result[1], 2, length(result[1])-2);
    result[2] := copy(result[2], 2, length(result[2])-2);
  end;

Und was hat es mit dem '"' aufsich?


n-regen - So 28.02.10 21:26

Der Teil soll Anführungszeichen am Anfang und Ende der Teilstrings rausfiltern.
Man könnte ihn auch noch verkürzen:

Delphi-Quelltext
1:
2:
3:
4:
  if result[0][1] = '"' then begin
    for i := 0 to 2
    do result[i] := copy(result[i], 2, length(result[i])-2);
  end;


Ach ja: ' leitet einen String ein. '"' ist also ein String, der nur ein Anführungszeichen enthält.


dummzeuch - So 28.02.10 21:49

user profile iconn-regen hat folgendes geschrieben Zum zitierten Posting springen:
Der Teil soll Anführungszeichen am Anfang und Ende der Teilstrings rausfiltern.
Man könnte ihn auch noch verkürzen:

Delphi-Quelltext
1:
2:
3:
4:
  if result[0][1] = '"' then begin
    for i := 0 to 2
    do result[i] := copy(result[i], 2, length(result[i])-2);
  end;



Ohne jetzt den restlichen Code genauer analysiert zu haben: Bist Du sicher, dass Result[0] niemals ein Leerstring sein kann? Wenn doch, knallt das da:


Delphi-Quelltext
1:
if result[0][1] = '"' then                    


twm


F34r0fTh3D4rk - So 28.02.10 22:42

user profile iconn-regen hat folgendes geschrieben Zum zitierten Posting springen:
Ach ja: ' leitet einen String ein. '"' ist also ein String, der nur ein Anführungszeichen enthält.

Ich weiß wie Strings in Delphi funktionieren :). Ich habe mich nur gewundert, was etwas so spezielles in einer allgemeinen explode Methode zu suchen hat.


Kha - So 28.02.10 22:47

user profile iconF34r0fTh3D4rk hat folgendes geschrieben Zum zitierten Posting springen:
Ich habe mich nur gewundert, was etwas so spezielles in einer allgemeinen explode Methode zu suchen hat.
Eine allgemeine Explode-Funktion mit exakt drei Output-Einträgen :mrgreen: ? Das mit den Anführungszeichen hätte ich heute aber gut gebrauchen [http://projecteuler.net/project/words.txt] können ;) ...


n-regen - Mo 01.03.10 01:30

user profile icondummzeuch hat folgendes geschrieben Zum zitierten Posting springen:
Ohne jetzt den restlichen Code genauer analysiert zu haben: Bist Du sicher, dass Result[0] niemals ein Leerstring sein kann? Wenn doch, knallt das da:

Delphi-Quelltext
1:
if result[0][1] = '"' then                    
Das könnte wirklich problematisch werden.
Welche Alternative ist da schneller?

Delphi-Quelltext
1:
if (result[0][1] <> ''and (result[0][1] = '"'then                    
(Delphi würde doch nach dem ersten Vergleich aufhören, wenn er FALSE zurückgibt, oder?)
oder

Delphi-Quelltext
1:
if pos('"', result[0][1]) = 1 then                    


aksdb - Mo 01.03.10 02:36

Spricht denn was dagegen, eine TStringList mit .Delimiter und .DelimitedText zu benutzen?


jfheins - Mo 01.03.10 10:29

user profile iconaksdb hat folgendes geschrieben Zum zitierten Posting springen:
Spricht denn was dagegen, eine TStringList mit .Delimiter und .DelimitedText zu benutzen?
Ja - die Geschwindigkeit ;)

Guck mal in die DP, da wurde sowas schonmal "durchoptimiert" http://www.delphipraxis.net/topic98278,0,asc,0.html ;)


F34r0fTh3D4rk - Mo 01.03.10 12:03

user profile iconn-regen hat folgendes geschrieben Zum zitierten Posting springen:
user profile icondummzeuch hat folgendes geschrieben Zum zitierten Posting springen:
Ohne jetzt den restlichen Code genauer analysiert zu haben: Bist Du sicher, dass Result[0] niemals ein Leerstring sein kann? Wenn doch, knallt das da:

Delphi-Quelltext
1:
if result[0][1] = '"' then                    
Das könnte wirklich problematisch werden.
Welche Alternative ist da schneller?

Delphi-Quelltext
1:
if (result[0][1] <> ''and (result[0][1] = '"'then                    
(Delphi würde doch nach dem ersten Vergleich aufhören, wenn er FALSE zurückgibt, oder?)
oder

Delphi-Quelltext
1:
if pos('"', result[0][1]) = 1 then                    

Ich glaube, bevor man sich solche Fragen stellen muss, sollte man sich den Rest seines Codes nochmal genau angucken, um ausschließen zu können, dass die Geschwindigkeitsbremse nicht doch ganz woanders liegt. Wie es aussieht hast du ja nur vor, einen String in drei Teile zu zerlegen. Das wird nur dann zu einem Zeitproblem, wenn du das sehr häufig machst. Was ist der genaue Kontext, in dem du deine Funktion verwendest? Vielleicht lässt sich da einiges mehr herausholen.


tif - Mo 01.03.10 12:32

Versteckt in der Unit HttpUtil gibt's noch (zumindest bei/ab 2009)


Delphi-Quelltext
1:
function StringToStringArray(const str: stringconst delim: string): TStringDynArray;                    


Ob die schneller ist weiss ich nicht, aber sie dampft den Quelltext auf eine Zeile ein.

Viel Erfolg
Tino