Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - String hinten an String anhängen


walter_b - Mi 16.07.08 12:04
Titel: String hinten an String anhängen
Hallo zusammen

Welches ist die optimalste Anwendung, um einem String hinten einen anderen anzuhängen? Ich möchte meinem String gerne 14 Nullen anhängen. Und ich habe mich gefragt, welche der verschiedenen Möglichkeiten die schnellste ist:


Delphi-Quelltext
1:
str:= str+'00000000000000';                    


oder


Delphi-Quelltext
1:
Insert('0000000000000', str, 1000); // Wie kann ich hier markieren, dass er ans Ende soll?                    


Oder gibt es eine bessere Lösung? Vielen Dank.


Fabian E. - Mi 16.07.08 12:16

Mit Insert kannst du als letzten Parameter den Index angeben wo der String eingefügt werden soll.
Da musst du halt die Länge der ursprünglichen Strings angeben.


walter_b - Mi 16.07.08 12:21

Und wenn ich die Länge nicht kenne, da sie variabel ist?

Und welche der beiden Varianten ist optimaler?


Fabian E. - Mi 16.07.08 12:22

Die Länge kann man über Length() herrausfinden.


Jerk - Mi 16.07.08 12:37

Ich würd die erste benutzen, da brauch man nich wissen wie Lang der String is.


Narses - Mi 16.07.08 12:45
Titel: Re: String hinten an String anhängen
Moin!

user profile iconwalter_b hat folgendes geschrieben:
Welches ist die optimalste Anwendung, um einem String hinten einen anderen anzuhängen? Ich möchte meinem String gerne 14 Nullen anhängen. Und ich habe mich gefragt, welche der verschiedenen Möglichkeiten die schnellste ist:
Von der Geschwindigkeit her sollte es bei sowas eigentlich egal sein, Probleme gibt es bei diesen "Aktionen" aber an einer anderen Stelle: beim Speicherverbrauch! :shock:

Das ist ist üblicherweise unkritisch:
user profile iconwalter_b hat folgendes geschrieben:

Delphi-Quelltext
1:
str:= str+'00000000000000';                    
Du solltest nur nicht die Nullen einzeln an den String anfügen, da dann unverhältnismäßig viel Speicher belegt wird. :idea:

cu
Narses


BenBE - Mi 16.07.08 12:47

Je nach dem, wie Du den String aufbaust, kann es aber auch durch Speicher-Zugriffe recht schnell erledigt werden. Voraussetzung dafür ist jedoch, dass Du die entgültige Länge des Strings im Vorhinein kurz berechnen kannst.

In dem Fall kann man nämlich auch das in der Form bauen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
var
    S: String;
    PS: ^PChar absolute S; //Nur tun, wenn man weiß, was man tut!
    L : Integer;
begin
    L := {...} //Berechnen
    SetLength(S, L);
    //Daten in den String füllen
    Inc(PS, L - 14); //PS zum Befüllen nutzen; am Ende sollte er 14 Zeichen vor dem Stringende stehen...

    FillChar(PS^, '0', 14); //14 Nullen anhängen
    Inc(PS, 14);

    //S enthält nun den vollständigen String ...
end;


Zur Erklärung: Durch das Vorausberechnen der Länge erspart man sich das ständige Realloziieren des Stringpuffers.

Alternativ sieht man häufig auch, dass der String auf eine viel größere Länge initialisiert wird, als wirklich benötigt und im Nachhinein auf die eigentliche Länge reduziert wird. Effekt ist ähnlich der Vorgehensweise wie das Vorausberechnen der Länge, jedoch mit dem Unterschied, dass zwei Aufrufe des Speichermnagers notwendig sind, jedoch mit dem Vorteil, dass diese Methode auch mit nicht im Vorhinein bekannten Längenangaben funktioniert, sofern man die maximal mögliche Länge nach OBEN abschätzen kann.

@Narses: Der Speicherverbrauch ist etwa das Doppelte des Resultierenden Strings (incl. Padding). Problematisch ist eher die Speicherfragmentierung, die den Speichermanager unnötig lahm macht.


walter_b - Mi 16.07.08 12:48

Ach so, okee, danke. Aber wegen der Auswirkung: Wenn das 1 Mia mal durchgeführt wird (und das wird es!), dann könnte da ein kleiner Effekt vielleicht doch grössere Auswirkungen haben, deshalb habe ich gefragt.


Boldar - Mi 16.07.08 14:19

ich würde das so lösen:

Delphi-Quelltext
1:
a:= concat (s1, '0000000000');                    


Dass ist glaube ich die schnellste Variante


nagel - Mi 16.07.08 15:53

Laut Delphi-Hilfe ist + schneller als Concat.


BenBE - Mi 16.07.08 16:10

Und + ist langsamer als direkt im String zu arbeiten ...


walter_b - Mi 16.07.08 20:31

Habe noch festgestellt, dass ich

+#0+#0+#0+#0+#0+#0+#0+#0+#0+#0+#0+#0+#0+#0 schreiben muss, anstelle der 14 Nullen, da ich Null-Bytes brauche und nicht Nullen. Oder gibt es einen eleganteren Weg dafür?


Yogu - Mi 16.07.08 20:52

Nehm doch anstatt von '0' die zwei Zeichen #0 - dann wird das Zeichen zum ASCII-Code 0 eingefügt. :idea:

------------------------------------------

Du hast es anscheinend schon selbst herausgefunden.

Eleganter könnte es evlt. so gehen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
var Len: Integer;
begin
  Len := Length(S);
  SetLength(S, Len+14);
  FillChar(S[Len+1], 14, #0);
end;


walter_b - Mi 16.07.08 21:04

Wenn ich ehrlich bin: Eleganz ist mir egal. Welches ist von der Geschwindigkeit her schneller?


Fabian E. - Mi 16.07.08 21:57

user profile iconwalter_b hat folgendes geschrieben:
Oder gibt es einen eleganteren Weg dafür?


user profile iconwalter_b hat folgendes geschrieben:
Wenn ich ehrlich bin: Eleganz ist mir egal. Welches ist von der Geschwindigkeit her schneller?


:lol:

Ne aber probiers doch einfach aus was schneller ist ;)
Lass das ganze 1.000.000 mal laufen und guck was schneller war ;)


Boldar - Mi 16.07.08 23:01

user profile iconYogu hat folgendes geschrieben:


Eleganter könnte es evlt. so gehen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
var Len: Integer;
begin
  Len := Length(S);
  SetLength(S, Len+14);
  FillChar(S[Len+1], 14, #0);
end;


Dass ist wohl definitiv der Schnellere Weg, da es "Hardwarenäher" ist


walter_b - Do 17.07.08 16:55

user profile iconBenBE hat folgendes geschrieben:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
var
    S: String;
    PS: ^PChar absolute S; //Nur tun, wenn man weiß, was man tut!
    L : Integer;
begin
    L := {...} //Berechnen
    SetLength(S, L);
    //Daten in den String füllen
    Inc(PS, L - 14); //PS zum Befüllen nutzen; am Ende sollte er 14 Zeichen vor dem Stringende stehen...

    FillChar(PS^, '0', 14); //14 Nullen anhängen
    Inc(PS, 14);

    //S enthält nun den vollständigen String ...
end;


Hab es Ausprobiert. Funktioniert Soweit auch, jedoch wird mir nach FillChar(PS^, '0', 14); und Inc(PS, 14); die Variabeln S und Wort gelöscht. Hier mein Skript:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
var
  S: String;
  PS: ^PChar absolute S;
  L : Integer;

[...]

    writeln(wort);
    L:=14;
    SetLength(S, L);
    S:=Wort;
    writeln(wort);
    writeln(s);
    Inc(PS, L - 14);
    writeln(s);
    FillChar(PS^, 14, '0');
    Inc(PS, 14);
    writeln(S);
    writeln(wort);


Die Ausgaben dazwischen: A, A, A, A, *nichts*, 0 (und beim nächsten Durchgang ist Wort plötzlich 1.)


Edit: kann ich auch anstelle von 0 einen Null-byte reinsetzen? #0 akzeptiert er nicht.


Boldar - Do 17.07.08 17:08


Delphi-Quelltext
1:
FillChar(PS^, 14, chr(0));                    


walter_b - Do 17.07.08 17:44

Okee, jetzt ist zwar das mit dem Null-byte da, aber die Variabeln werden mir immernoch gelöscht. Warum das? Was läuft hier falsch?


walter_b - Do 17.07.08 19:48

Ich habe jetzt das Skript von Yogu ausprobiert, doch auch hier läuft etwas schief.

Folgendes ist der Code:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
    Len := Length(Wort);
    SetLength(Wortchen, Len+14);
    wortchen:=Wort;
    writeln(Len);
    FillChar(wortchen[Len+1], 14, 'g' );
    writeln(wortchen);


Diese Werte werden ausgegeben:
Len bei den ersten 10 Durchgängen 1 (richtig so)
Bei wortchen geht er dem Alphabet nach (so wie es das Programm vorschreiben würde). Doch wieso setzt er das G nicht? Ersetze ich diese Zeile durch


Delphi-Quelltext
1:
FillChar(wortchen[Len], 14, 'g' );                    


dann habe ich immer an der ersten Stelle ein g, während der rest normal weitergeht. Aber wieso ignoriert er die 14?


BenBE - Do 17.07.08 21:32

Sorry, bei dem PChar absolut S war ein ^ zu viel ... Ohne sollte es gehen ...


walter_b - Do 17.07.08 22:37

---Moderiert von user profile iconNarses: Beiträge zusammengefasst---

user profile iconBenBE hat folgendes geschrieben:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
var
    S: String;
    PS: PChar absolute S; //Nur tun, wenn man weiß, was man tut!
    L : Integer;
begin
    L := {...} //Berechnen
    SetLength(S, L);
    //Daten in den String füllen
    Inc(PS, L - 14); //PS zum Befüllen nutzen; am Ende sollte er 14 Zeichen vor dem Stringende stehen...

    FillChar(PS^, '0', 14); //14 Nullen anhängen
    Inc(PS, 14);

    //S enthält nun den vollständigen String ...
end;



Wie genau stellst du dir das füllen des Strings vor? Mit S:=Wort; löscht es bei mir die Variabel Wort.
Und L ist die schlussendliche Länge des ganzen Strings, also nach einfüllen der 0en und allem, oder?

Hier nochmal mein Skript, habe noch bisschen rumgespielt, aber geht irgendwie nicht.


So gibt es eine Invalid Pointer Operation. Wird wortchen:=S auskommentiert, "funktioniert" es zwar, jedoch wird die Variabel Wort manipuliert, stimmt also nicht mehr. Wahrscheinlich aufgrund von Pointer!?



Edit: Danke an Narses, wollte das erste Posting eigentlich löschen, aber ging nicht ;)