Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Leerzeichen in String einfügen (https://www.delphipraxis.net/188047-leerzeichen-string-einfuegen.html)

majornudelholz 26. Jan 2016 19:50

Leerzeichen in String einfügen
 
Hallo,

ich brauche unbedingt Hilfe, im Internet habe ich sonst nichts gescheites gefunden...
Derzeit versuche ich vergeblich Unterstriche in ein String einzufügen, natürlich in bestimmter Reihenfolge!
Aber erst einmal zur Problemstellung:
Nach Eingabe einer Zeichenkette von max. 128 Zeichen soll nach Betätigung des Buttons alle 4 Zeichen ein Unterstrich eingefügt werden!

Meine bisherige Lösung sieht wie folgt aus:
Code:
procedure TForm1.unterstrich(text:string);
var i:integer; var textn:string;
begin
  textn:=text;
   for i:=1 to length(textn) do
      begin
         if ((i mod 3) = 0) then
        begin
          insert('_', textn, i);
        end;
      end;
  label2.caption:=textn;
end;
Wie ihr sicher unschwer erkennen könnt habe ich das Hauptproblem, dass er durch das einfügen der Unterstriche die Zeichenkette verschiebt & die Zählschleife nicht mehr bis an die letzten Zeichen 'heranreicht'... Hatte überlegt, ob das evtl. iterativ lösbar ist. Habe nur keine Idee wie.. :roll:

Wäre für jegliche Hilfe hierbei dankbar! :)

blawen 26. Jan 2016 19:53

AW: Leerzeichen in String einfügen
 
Wie wäre es mit einer Repeat...Until Schleife?

majornudelholz 26. Jan 2016 19:55

AW: Leerzeichen in String einfügen
 
Zitat:

Zitat von blawen (Beitrag 1328323)
Wie wäre es mit einer Repeat...Until Schleife?

Hatte ich auch schon versucht. Nur habe ich wie gesagt leider keine weiteren Ideen. :(

Luckie 26. Jan 2016 20:17

AW: Leerzeichen in String einfügen
 
Zitat:

Zitat von majornudelholz (Beitrag 1328324)
Zitat:

Zitat von blawen (Beitrag 1328323)
Wie wäre es mit einer Repeat...Until Schleife?

Hatte ich auch schon versucht.

Und was war das Ergebnis?

majornudelholz 26. Jan 2016 20:34

AW: Leerzeichen in String einfügen
 
Zitat:

Zitat von Luckie (Beitrag 1328325)
Zitat:

Zitat von majornudelholz (Beitrag 1328324)
Zitat:

Zitat von blawen (Beitrag 1328323)
Wie wäre es mit einer Repeat...Until Schleife?

Hatte ich auch schon versucht.

Und was war das Ergebnis?

Naja, hatte damals keins, weil ich nicht wusste, wie... Habe nun aber eine Idee bzw. es klappt auch schon! :)
Trotzdem danke für die Mühen! ... und die schnellen Antworten! :-D

Code:
procedure TForm1.leerzeichen(text:string);
var i:integer;
begin
  for i:=1 to 192 do
         if ((i mod 3) = 0) then begin
        //delete(text, i, 1);
        insert(' ', text, i);
        end;
  trimright(text);
  label2.caption:=text;
end;
... so hat's jetzt geklappt!

Mavarik 27. Jan 2016 00:59

AW: Leerzeichen in String einfügen
 
Zitat:

Zitat von majornudelholz (Beitrag 1328326)
Code:
procedure TForm1.leerzeichen(text:string);
var i:integer;
begin
  for i:=1 to 192 do
         if ((i mod 3) = 0) then begin
        //delete(text, i, 1);
        insert(' ', text, i);
        end;
  trimright(text);
  label2.caption:=text;
end;
... so hat's jetzt geklappt!

Wie wäre es mit

Delphi-Quellcode:
procedure TForm1.leerzeichen(Const Text:string);
var
  _Result : String;
  PSource,PDest,PEnd : PChar;
  Count : Integer;
begin
  Setlength(_Result,length(Text)+Length(Text) div 4);
  PSource := @Text[Low(Text)];
  PDest  := @_Result[Low(_Result)];
  PEnd   := @Text[High(Text)];
  Count  := 0;

  while PSource <= PEnd do
    begin
      PDest^ := PSource^;
      inc(PDest);
      inc(PSource);
      inc(Count);
      if Count = 4 then
        begin
          Count := 0;
          PDest^ := ' ';
          inc(PDest);
        end;
    end;
  label2.caption:=_Result;
end;
"Bisschen" schneller...

Dejan Vu 27. Jan 2016 06:48

AW: Leerzeichen in String einfügen
 
Bei 192 Zeichen dürften das 'schneller' weit jenseits der Messbarkeit sein.
Delphi-Quellcode:
var
  i : Integer;
 
begin
  i := 4; // Erste Einfügeposition hinter der 4 Stelle.
  while i < Length(Text) do begin
    insert (Text, i,'_');
    inc(i,5); // weil man ja nun 5 Zeichen weiter rutschen muss
  end;
End;
Getippt und nicht getestet. Sollte aber so oder ähnlich gehen.

Übrigens: Bisschen kleiner, leichter zu verstehen, geradliniger. ;-)

HolgerX 27. Jan 2016 07:23

AW: Leerzeichen in String einfügen
 
Hmm..

Oder mach es doch einfach mit einer rückwärts laufenden Schleife ;)

Delphi-Quellcode:
function InsertUnderLine(AText : string; aPos : byte):string;
var
  i : integer;
begin
  result := AText;
  for i := length(AText)-1 downto 1 do begin
    if ((i mod aPos) = 0) then
      insert('_',result,i+1);
  end;
end;
Mit 'for' kann man nicht nur 'hochzählen' sondern auch 'runterzählen' ;)

Sir Rufo 27. Jan 2016 08:00

AW: Leerzeichen in String einfügen
 
Oder mit ganz wenigen String-Kopierorgien und einem wahlfreien String den man dort einschieben kann:
Delphi-Quellcode:
function StrInsertEveryNthPos( const AStr, AInsertStr: string; APos: integer ): string;
var
  OffSet                       : integer;
  ResLen, ResIdx, StrIdx, InsIdx: integer;
begin
  // OffSet for ZEROBASED STRINGS
  OffSet := 1 - low( string );

  // Calculate result length

  ResLen := ( Length( AStr ) div APos );
  if Length( AStr ) mod APos = 0
  then
    Dec( ResLen );
  ResLen := Length( AInsertStr ) * ResLen;
  ResLen := ResLen + Length( AStr );

  SetLength( Result, ResLen );

  // Build result

  ResIdx := 1;

  for StrIdx := 1 to Length( AStr ) do
    begin
      Result[ ResIdx - OffSet ] := AStr[ StrIdx - OffSet ];
      Inc( ResIdx );

      // Insert the AInsertStr

      if ( StrIdx mod APos = 0 ) and ( StrIdx < Length( AStr ) )
      then
        for InsIdx := 1 to Length( AInsertStr ) do
          begin
            Result[ ResIdx - OffSet ] := AInsertStr[ InsIdx - OffSet ];
            Inc( ResIdx );
          end;
    end;
end;

EgonHugeist 27. Jan 2016 08:12

AW: Leerzeichen in String einfügen
 
Da es sich explizit um Quad Folgen handelt..

@Maverik ungetestet aus dem Handgelenk geschüttelt:
edit:
Hab's nun doch getestet und da hat noch das mod gefehlt, sonst hängt man auch noch '_' and den letzten quad an

Code:
function leerzeichen(Const Text: String): String;
type PMyQuadMover = {$IFDEF UNICODE}PUInt64{$ELSE}PLongWord{$ENDIF};
var
  Src, Dest, PEnd: PChar;
begin
  if Text = '' then
    Result :=''
  else begin
    SetLength(Result,length(Text)+(Length(Text) div 4)-Ord(Length(Text) mod 4 = 0));
    PEnd := PChar(@Text[Length(Text)])-4;
    Dest := Pointer(Result);
    Src := Pointer(Text);
    while (Src <= PEnd) do begin//making a quad processing loop
      PMyQuadMover(Dest)^ := PMyQuadMover(Src)^;
      (Dest+4)^ := '_';
      Inc(Dest, 5);
      Inc(Src, 4);
    end;
    Inc(PEnd, 4);
    while Src < PEnd do //processing final chars
    begin
      Dest^ := Src^;
      Inc(Src);
      Inc(Dest);
    end;
    Dest^ := Src^; //null term save
  end;
end;
Das wäre schnell.. man könnte die Loops auch nach auf octets erhöhen, auf RefCount und Length vorher testen usw .. :-D

Mavarik 27. Jan 2016 09:57

AW: Leerzeichen in String einfügen
 
@Sir Rufo sehr nice und wie immer natürlich variable und "zu gebrauchen" :thumb:
@EgonHugeist der Quadmove ist natürlich sehr nett, aber da durch brauchst Du drumrum natürlich mehr...
Wäre zu testen ob der Quadmove das wett macht...

Alle Routinen mit Insert - gehen natürlich gar nicht - weil der String nicht nur 192 Zeichen, sondern auch mal 20MB lang seinen kann... :stupid:

Die Frage ist, wenn der String Steuerzeichen hat - wie #13#10 oder #10#13 oder nur #10 oder #13... Beginnt der Zähler dann bei 0? Und natürlich darf das " " oder "_" nicht zwischen #13_#10 eingefügt werden...

Kommt Leute da geht noch was...

EgonHugeist 27. Jan 2016 10:48

AW: Leerzeichen in String einfügen
 
@mav

meine Portierung hält sich exakt an das, was der TE wollte. Ich halte es für abwägig, das LineEndings oder andere ctrl chars im TEdit landen...

Klar geht noch was:

Code:
function EH_QuadUnderScoreFillerBy4(Const Text: String): String;
type PMyQuadMover = {$IFDEF UNICODE}PUInt64{$ELSE}PLongWord{$ENDIF};
var
  Src, Dest, PEnd: PChar;
  SrcLen: Integer;
begin
  if Text = '' then
    Result :=''
  else begin
    SrcLen := PLongInt(NativeUInt(Text) - SizeOf(LongInt))^; //fast get src length
    Src := Pointer(Text);
    PEnd := Src+SrcLen-5;
    if (Pointer(Result) = nil) or //result unassigned?
       (PLongInt(NativeUInt(Result) - SizeOf(LongInt))^ <> SrcLen) {PStrRec.Len} or //length different?
       (PLongInt(NativeUInt(Result) - (SizeOf(LongInt) shl 1))^ <> 1) {PStrRec.RefCnt} then //no unique string?
      SetLength(Result,SrcLen+((SrcLen-1) shr 2));
    Dest := Pointer(Result);
    while (Src <= PEnd) do begin//making a quad processing loop
      PMyQuadMover(Dest)^ := PMyQuadMover(Src)^;
      (Dest+4)^ := '_';
      Inc(Dest, 5);
      Inc(Src, 4);
    end;
    Inc(PEnd, 4);
    while Src < PEnd do //processing final chars
    begin
      Dest^ := Src^;
      Inc(Src);
      Inc(Dest);
    end;
    Dest^ := Src^; //null term save
  end;
end;
und nu 2 quad moves in einer loop (macht nur sinn, wenn der String länger ist)
Code:
function EH_QuadUnderScoreFillerBy8(Const Text: String): String;
type PMyQuadMover = {$IFDEF UNICODE}PUInt64{$ELSE}PLongWord{$ENDIF};
var
  Src, Dest, PEnd: PChar;
  SrcLen: Integer;
begin
  if Text = '' then
    Result :=''
  else begin
    SrcLen := PLongInt(NativeUInt(Text) - SizeOf(LongInt))^; //fast get src length
    Src := Pointer(Text);
    PEnd := Src+SrcLen-9;
    if (Pointer(Result) = nil) or //result unassigned?
       (PLongInt(NativeUInt(Result) - SizeOf(LongInt))^ <> SrcLen) {PStrRec.Len} or //length different?
       (PLongInt(NativeUInt(Result) - (SizeOf(LongInt) shl 1))^ <> 1) {PStrRec.RefCnt} then //no unique string?
      SetLength(Result,SrcLen+((SrcLen-1) shr 2));
    Dest := Pointer(Result);
    while (Src <= PEnd) do begin//making a octed processing loop
      PMyQuadMover(Dest)^ := PMyQuadMover(Src)^;
      (Dest+4)^ := '_';
      PMyQuadMover(Dest+5)^ := PMyQuadMover(Src+4)^;
      (Dest+9)^ := '_';
      Inc(Dest, 10);
      Inc(Src, 8);
    end;
    Inc(PEnd, 8);
    if ((Src+4) <= PEnd) then begin//making final quad move
      PMyQuadMover(Dest)^ := PMyQuadMover(Src)^;
      (Dest+4)^ := '_';
      Inc(Dest, 5);
      Inc(Src, 4);
    end;
    while Src < PEnd do //processing final chars
    begin
      Dest^ := Src^;
      Inc(Src);
      Inc(Dest);
    end;
    Dest^ := Src^; //null term save
  end;
end;
Jup mehr drum herum, ist nicht abzustreiten. Jags mal durch nen Tick-Counter mit 'ner loop x 5.000.000 ich garantier dir der Unterschied ist riesig.

Das gilt im PurePascal erst mal zu Schlagen! Wer traut sich?

Gruß vom ZeosDevTeam

Edit: a shr vs shl war verdreht, sorry sonst funzt das "Reuse-Result" nicht

Sir Rufo 27. Jan 2016 10:49

AW: Leerzeichen in String einfügen
 
Zitat:

Zitat von Mavarik (Beitrag 1328396)
Die Frage ist, wenn der String Steuerzeichen hat - wie #13#10 oder #10#13 oder nur #10 oder #13... Beginnt der Zähler dann bei 0? Und natürlich darf das " " oder "_" nicht zwischen #13_#10 eingefügt werden...

Dann kommt wieder Composite ins Spiel.
  • String in Zeilen splitten
  • Jede Zeile durch die Routine
  • Zeilen wieder zusammenfassen
Eine zu starke Spezialisierung macht keinen Sinn, denn mal ist ein Zeilenumbruch #10 mal #13 mal #13#10 ... und dann werden die Zeilen an weiß der Geier woran umgebrochen (HTML bei einem <br>)

himitsu 27. Jan 2016 12:29

AW: Leerzeichen in String einfügen
 
Zitat:

Zitat von Sir Rufo (Beitrag 1328406)
Dann kommt wieder Composite ins Spiel.

Wie Recht du doch hast. :stupid:

A: Surrogates und bei ANSI die MultiByte-Zeichensätze > https://de.wikipedia.org/wiki/UTF-16
B: Ä kann auch als A mit ¨ geschrieben werden > https://en.wikipedia.org/wiki/Precomposed_character https://en.wikipedia.org/wiki/Composite_character https://de.wikipedia.org/wiki/%C3%84 https://de.wikipedia.org/wiki/Trema https://de.wikipedia.org/wiki/Unicod...tische_Zeichen ...

MSDN-Library durchsuchenCharNext / MSDN-Library durchsuchenCharNextEx

EgonHugeist 27. Jan 2016 12:42

AW: Leerzeichen in String einfügen
 
Zum Spaß, hab ich mal ne kleine Benchmark Sache gemacht..

Zitat:

Benchmarking(x16 x 2.000.000):
Autor: Maverik Function: MaverikQuadUnderScoreInjector between 9734

Benchmarking(x16 x 2.000.000):
Autor: EgonHugeist Function: leerzeichen between 3500

Benchmarking(x16 x 2.000.000):
Autor: EgonHugeist Function: EH_QuadUnderScoreInjectorBy4 between 3453

Benchmarking(x16 x 2.000.000):
Autor: EgonHugeist Function: EH_QuadUnderScoreInjectorBy8 between 3437
Habe mal laaaange strings unterdrückt, da MaverikQuadUnderScoreInjector etwas laaange braucht.
@Sir Rufo
Darf ich deine Resultate zum Spaß beihängen? Habe ne kleine Test-Unit gebastelt. Mit deiner StrInsertEveryNthPos function.. :pale:

Sonst würd ich die wieder rausnehmen :cyclops: und nur für Maverik der Validierung halber anhängen..

Sir Rufo 27. Jan 2016 12:56

AW: Leerzeichen in String einfügen
 
Wieso denn nicht? :stupid:

Keine Hemmungen ... das halte ich schon aus :wink:

Mavarik 27. Jan 2016 13:13

AW: Leerzeichen in String einfügen
 
Zitat:

Zitat von EgonHugeist (Beitrag 1328434)
Zum Spaß, hab ich mal ne kleine Benchmark Sache gemacht..

3 Sachen...

1. Zeig mal Deine Testroutine.
2. Vergleiche mal die Version mit der Insert variante.
3. Schreibe bitte meinen Nickname richtig... Danke

EgonHugeist 27. Jan 2016 13:34

AW: Leerzeichen in String einfügen
 
Liste der Anhänge anzeigen (Anzahl: 1)
@Sir Rufo

:thumb: fair und kannst was wegstecken!

Vorab, in !Mavarik!'s und deinen Versionen habe ich kleine compilierungs Änderungen gemacht.
Gibt es da Einwände ... sofort losbrüllen! :shock: Mein altes XE hat's nicht fressen wollen.

geht los habe den Shift auf 12 erhöht (siehe Test):

Zitat:

Benchmarking(x12 x2000000:
Autor: Mavarik Function: MavarikQuadUnderScoreInjector TickCount: 37719

Benchmarking(x12 x2000000:
Autor: EgonHugeist Function: leerzeichen TickCount: 15140

Benchmarking(x12 x2000000:
Autor: Sir Rufo Function: StrInsertEveryNthPos TickCount: 324188

Benchmarking(x12 x2000000:
Autor: EgonHugeist Function: EH_QuadUnderScoreInjectorBy4 TickCount: 15047

Benchmarking(x12 x2000000:
Autor: EgonHugeist Function: EH_QuadUnderScoreInjectorBy8 TickCount: 9437
Meine Funktionen würden unter 64Bit vielleicht noch besser laufen, da der UInt64 move da performanter ist als der 2x4Byte move, den die 32Bit IDE reinfummelt. Meine letzte Version läuft allen davon, desto länger der String wird. Da der TE aber nur von 128 Zeichen ausgeht tut es Version 1 und 2 genau sogut, wie Mavarik's version.

Eine Validierung fehlt, da dies die "reine" Geschwindigkeit verfälscht.

@Mav
die Funktionen mit den inserts hab ich gleich weggelassen. Darfst sie aber gerne hinzufügen, wenn die Autoren nix dagegen haben.

EgonHugeist 27. Jan 2016 15:27

AW: Leerzeichen in String einfügen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hab mal das insert von Dejan Vu in gefixter Version hinzugefügt, Mavarik's Version gefixt und meine Änderung an Sir Rufo's version kontrolliert und überarbeitet..

Das insert() kommt, wie erwartet, im Vergleich nach gefühlten Jahren wieder..

Edit: Wird es überhaupt mit der Aufage fertig? Ich habs nach 30min abgebrochen.

Alle Funktionen liefern nun gültige Resultate.

Neue Verison ist angehängt.

Wer keine Zeit hat, kommentiert die insert Version aus.

EgonHugeist 27. Jan 2016 17:32

AW: Leerzeichen in String einfügen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Sitze grad beim Abendessen.

:oops::oops:

Sorry, da Fehler in meiner letzten Version, welche ich hochgeladen und deren Resultate gepostet habe..
habe den DupeString Shift auf 10 limitiert, um mal bei der Insert-Variante noch vor morgen früh ein Ergebnis zu bekommen:

Zitat:

Benchmarking DupeString('xyz', shl^0..10) Iterations: 2000000:
Autor: Mavarik Function: MavarikQuadUnderScoreInjector TickCount: 9735

Benchmarking DupeString('xyz', shl^0..10) Iterations: 2000000:
Autor: EgonHugeist Function: leerzeichen TickCount: 3500

Benchmarking DupeString('xyz', shl^0..10) Iterations: 2000000:
Autor: Sir Rufo Function: StrInsertEveryNthPos TickCount: 85719

Benchmarking DupeString('xyz', shl^0..10) Iterations: 2000000:
Autor: EgonHugeist Function: EH_QuadUnderScoreInjectorBy4 TickCount: 3469

Benchmarking DupeString('xyz', shl^0..10) Iterations: 2000000:
Autor: EgonHugeist Function: EH_QuadUnderScoreInjectorBy8 TickCount: 3437

Benchmarking DupeString('xyz', shl^0..10) Iterations: 2000000:
Autor: Dejan Vu Function: DejanVuQuadUnderScoreInjector TickCount: 579688

Dejan Vu 27. Jan 2016 18:19

AW: Leerzeichen in String einfügen
 
Bahnbrechende Erkenntnis bei einem Codeschnippsel, das für einen Anfänger gedacht ist und dann in einem Buttonclick einmalig auf maximal 128 Zeichen losgelassen wird. Ich schlage vor, die beste Funktion mit der Parameterübergabeoption 'register' zu versehen, dann kann man nochmal einiges Rauskitzeln.

Eins ist sicher: Verwirrt ist der gute Mann (3 Beiträge, D7, Probleme in einer kleinen Schleife)bestimmt nicht. :wall:

Leute, im Ernst: Ist hier nicht ausnahmsweise angebracht (ja, ich weiß, es gibt Programmierer, die lehnen das ab), die einfachste Variante vorzuschlagen?

PS: Als Performancebooster war mein Vorschlag übrigens gar nicht gedacht, sondern als Versuch, die einfachste und verständlichste Version zu präsentieren. Falls das jemanden aufgefallen ist.

EgonHugeist 28. Jan 2016 03:40

AW: Leerzeichen in String einfügen
 
@Dejan Vu
Der TE ist in #5 bereits auf eine Lösung gekommen. Warum du dem TE in #7 wieder eine 2. Variante von #5 presentierst wird, erschließt sich mir nicht. Er hat gefragt, ihm ist das Insert() als eigene Lösung zuzugestehen. Völlig in Ordnung, er lernt es ja gerade.

Mavarik hat ihm in #6 wohlwollend zeigen wollen, wie man das schneller machen... Warum? Nun ich würde davon ausgehen, das der TE eines schönen Tages Automatisierungen vornehmen müßte, wenn nicht mit dem Beispiel, dann an anderer Stelle und in anderer Variante. Nun neigt man dazu bereits vorhandenen Code wieder zu nutzen, da es ja schon wunderbar mit TForm1.leerzeichen(text:string) funktioniert hat.
Ich bin nicht der Meinung, daß hier irgendwer den TE verwirren wollte, sondern auf sein konkretes Bsp. bezogen, mögliche Varianten der Herangehensweisen aufzeigen wollte.

Mavarik's Version (gefixt) und die von Sir Rufo zeigen ihm nur, daß man eben die String-Copy Orgien, ab 'ne Iteration > 2 wirklich vermeiden sollte. Das lernt er aus den Benchmarks: Numbers are talking!

Der TE kann sich diverse Erkenntnisse an allen Nachfolgenden Bsp. aneigenen. Wie: benutze Pointer-Inkrementierungen oder den Index des Strings, kalkuliere und reserviere den Speicher nur !einmal! und schieb rüber, was du braucht, schreibe kleine Funktionen und lagere diese aus ..... zum Bespiel.

Durch Mavarik's "schneller" in #6 ist mir bei der Aufgabe sofort aufgefallen, das man seiner Version noch so einiges abringen könnte ->#7
Ein wiederholtes "da geht noch was" und in Fragestellung, ob mein größeres Code-Konstrukt etwas bessere und messbare Ergebnisse liefert -> Benchmarks. Irrglaube wer denkt, wenig Code bringt in jedem Falle viel Geschwindigkeit!

Wenn der TE eines Tages sportliche/variable/hochgeschwindigkeits Resultate liefern sollte ... jeder hier wollte ihm auf seine Art und Weise zeigen, wie es geht. Uns hat man es ja auch mal gezeigt, oder nicht? Du hast ihm wiederholt, wie man es als Anfänger machen darf und man es bei mehr Erfahrung nicht machen sollte, warum auch immer. Er kann mit den zusätzlichen Code-Bsp. machen, was er möchte. Ist es zu kompliziert, sollte er weitere Erfahrungen sammeln und vielleicht später darauf zurückgreifen.

Ich habe hierbei auch etwas gelernt:
Code:
    if (Pointer(Result) = nil) or //result unassigned?
       (PLongInt(NativeUInt(Result) - SizeOf(LongInt))^ <> SrcLen) {PStrRec.Len} or //length different?
       (PLongInt(NativeUInt(Result) - (SizeOf(LongInt) shl 1))^ <> 1) {PStrRec.RefCnt} then //no unique string?
      SetLength(Result,SrcLen+((SrcLen-1) shr 2));
Für hoch performante String functions war ich es gewohnt erst den String-Refcount und die Länge zu testen, bevor ich ein SetLength() calle. Die älteren IDE's haben in jedem Falle einen neuen Unique-String erzeugt. Nun scheint mir das dieser Test schon implizit dem SetLength drin ist. Oder baut das der Compiler neuerdings direkt ein? Das war nicht immer so, und gilt herauszufinden, seit welcher Version sich Delphi so verhält. Klar ich spare den Call aber der Code wird unleserlich und für jemanden, der davon keine Ahnung hat, völlig banane.

@Mavarik
Ist der Test so in Ordnung für dich? Ergebnisse akzeptiert?

Dejan Vu 28. Jan 2016 07:15

AW: Leerzeichen in String einfügen
 
Die Lösung von #5 ist ja nicht korrekt, da sie die Länge des Strings ignoriert, daher die #7. Daraufhin hat Mavarik sein Pointerzeugs (nicht falsch verstehen, es ist 'good stuff') gepostet und dann hat sich der Thread in Richtung Performanceoptimierung degeneriert. So wird ein Schuh draus, gelle?

Ich fand es einfach amüsant, am Thema vorbei zu optimieren. Normalerweise macht man das dann in einem eigenen Thread, z.B. mit dem Titel 'Kata: Performanceoptimierung beim "Einfügen in Strings"'. Oder so ähnlich. Dann machen auch mehr Leute mit und es kann gefachsimpelt werden.

PS: Nicht falsch verstehen: Ich liebe Performanceoptimierungen.

himitsu 28. Jan 2016 08:13

AW: Leerzeichen in String einfügen
 
Zitat:

Zitat von Dejan Vu (Beitrag 1328515)
Ich schlage vor, die beste Funktion mit der Parameterübergabeoption 'register' zu versehen, dann kann man nochmal einiges Rauskitzeln.

Ähhhhhhhhhhhhhhhh, Nö.

Das macht Delphi/Pascal standardmäßig von Haus aus.

Mavarik 28. Jan 2016 09:16

AW: Leerzeichen in String einfügen
 
Zitat:

Zitat von Dejan Vu (Beitrag 1328515)
Leute, im Ernst: Ist hier nicht ausnahmsweise angebracht (ja, ich weiß, es gibt Programmierer, die lehnen das ab), die einfachste Variante vorzuschlagen?

emmmmm nöö

Wir haben ja oft hier Neulinge die mit Delphi anfangen. Nach der einfachen Regel:

Make it Work Make it Right Make It Fast!

Ich gebe Dir recht, dass für den TE die Insert Variante ausreichend ist. Aber auch er sollte im Hinterkopf behalten, dass es zwar funktioniert, aber nicht gerade performant ist.

Daher finde ich meine Variante als gutes Beispiel. (Die RTL macht es auch so) Für so einen Fall "C-Like" mit PChars zu arbeiten. Dabei bleibt die Routine immer noch übersichtlich. Und ist immerhin 60x schneller... Wir regen hier nicht von 2x oder 3x!

Sir Rufo's Variaten hat aber auch Ihren Platz - wenn auch nicht so schnell - kann man diese Routine, so übernehmen und als 1. Routine in seine eigene Procedurensammlung packen - weil allgemein gültig... Dabei immerhin auch 6,7x schneller als die Insert Variante. Not Bad für eine allgemeingültige Routine...

Hugo hat dann gezeigt... Richtig Kopieren bringt nochmal eine mehr als doppelt so schnelle Version hervor. Auch wenn die Routine dann nicht mehr ganz so übersichtlich ist.

Eigentlich wollte ich noch eine Thread-Variante bauen, die den String erst auf 4 Worker-Thread aufteilt, aber ich hatte leider gestern keine Zeit mehr... Vielleicht macht es ja noch einer...

Im Großen und Ganzen... Finde ich den Thread sehr gelungen, auch wenn das Thema jetzt damit abgeschlossen ist. Wenn jeder Programmierer - selbst bei so wenigen Zeilen Source - die Performance Überlegungen nicht außer acht lassen würde, brächten wir heute nicht 3,5 GHz, um Dinge zu erledigen, die früher mit 25 MHz möglich waren... (bitte nicht darauf eingehen) 8-)

Mavarik

EgonHugeist 28. Jan 2016 10:54

AW: Leerzeichen in String einfügen
 
@Mavarik

so da gibt jetzt der "Hugo" mal noch abschließend seinen Senf hinzu.

Dem Link stimme ich vollends zu.

Bitte schau es dir mal genauer an, was ich mache. Verstanden hast du es auch noch nicht. Der Trick ist nicht das kopieren. Das könnte man in den Quad folgen auch so lösen:
Code:
.....
Dest^ := Src^;
(Dest+1)^ := (Src+1)^;
(Dest+2)^ := (Src+3)^;
(Dest+3)^ := (Src+3)^;
.....
Und es würde nachwievor jede hier dargestellte Version schlagen.

Der Trick ist das Decrementieren des PEnd-Pointers um die Länge des concat-Strings. Somit kann ich in jedem Falle den gesamten concat innerhalb Lenght(Result) div Length(ConcatStr) Loop durchlaufen und ich brauch auch nicht mehr auf die Position zu achten, damit die N-te ein String-X wird.

Somit läuft mein code mit 4x weniger loops als der deine.

Die Loops waren das Performance Problem bei dir und bei Sir Rufo gleich doppelt + der Bremse, daß die IDE innerhalb jeder Loop die Offsets neu incrementieren muß, da er Str[x] offsets nutzt.

Sir Rufos Bsp könnte man auch so darstellen (nicht hauen wenns jettzt nicht geht -> ungetestet):
Code:
function EH_StrInsertEveryNthPos(const AStr, AInsertStr: string; APos: Integer): string;
var
  AStrLen, AInsertStrLen, ResLen, ConcatLen: Integer;
  PAStr, Dest, PEnd: PChar;
begin
  if AStr = '' then
    Result := ''
  else begin
    AStrLen := PLongInt(NativeUInt(AStr) - SizeOf(LongInt))^; //fast get AStr length
    if (AInsertStr = '') or (AStrLen <= APos) then
      Result := AStr
    else begin
      AInsertStrLen := PLongInt(NativeUInt(AInsertStr) - SizeOf(LongInt))^; //fast get AInsertStr length
      ResLen := AStrLen+((( AStrLen div APos ) - Ord(AStrLen mod APos = 0))*AInsertStrLen);
      ConcatLen := APos+AInsertStrLen;
      SetLength(Result, ResLen);
      PAStr := Pointer(AStr);
      Dest := Pointer(Result);
      PEnd := (PAStr+AStrLen)-APos; <<<<<<<<<<<<<<----- Da hat der Frosch die Locken (:
      while (PAStr < PEnd) do begin
        System.Move(PAStr^, Dest^, APos{$IFDEF UNICODE} shl 1{$ENDIF});
        System.Move(Pointer(AInsertStr)^, (Dest+APos)^, AInsertStrLen{$IFDEF UNICODE}shl 1{$ENDIF});
        Inc(Dest, ConcatLen);
        Inc(PAStr,APos);
      end;
      System.Move(PAStr^, Dest^, ((PEnd+APos) - PAStr){$IFDEF UNICODE} shl 1{$ENDIF});
    end;
  end;
end;
und nun noch mal für den Laien verständlicher mit Anleitung und ohne Low-Level code:
Delphi-Quellcode:
function EH_StrInsertEveryNthPos(const AStr, AInsertStr: string; APos: Integer): string;
var
  AStrLen, AInsertStrLen, ResLen, ConcatLen: Integer;
  PAStr, Dest, PEnd: PChar;
begin
  if AStr = '' then
    Result := ''
  else begin
    { speichere die Länge das Strings, in welchen die Inserts gemacht werden sollen }
    AStrLen := Length(AStr);
    if (AInsertStr = '') or (AStrLen <= APos) then
      Result := AStr
    else begin
      { Vorbereitung }
      AInsertStrLen := Length(AInsertStr); //speichere die Länge des AInsertStrings
      ConcatLen := APos+AInsertStrLen; //speichere die Länge der Fragmente welche im Resultat zusammengesetzt werden

      ResLen := AStrLen+((( AStrLen div APos ) - Ord(AStrLen mod APos = 0))*AInsertStrLen); //kalkuliere die Länge des Resultats
      SetLength(Result, ResLen); //reserviere den benötigten Speicher für das Resultat

      PAStr := Pointer(AStr); //Speichere den Pointer von AStr
      Dest := Pointer(Result); //Speichere den Pointer von Result
     
      { Speichere den Pointer des letzten Chars von AStr abzüglich die Länge von APos }
      { um die Wiederholungen der nachfolgenden Schleife um Faktor APos zu reduzieren } 
      PEnd := (PAStr+AStrLen)-APos;

      { fülle das Resultat mit den Daten }
      while (PAStr < PEnd) do begin
        { da wir PEnd um die Länge von APos reduziert haben, ist es garantiert, das wir NIE die Länge von AStr überschreiten }
       
        { kopiere eine Menge von APos Chars von der derzeitig gemerkten Stelle des AStr in das Resultat }
        System.Move(PAStr^, Dest^, APos*SizeOf(Char));  
        { kopiere AInsertString in das Resultat nach den zuletzt kopierten Daten }
        System.Move(Pointer(AInsertStr)^, (Dest+APos)^, AInsertStrLen *SizeOf(Char));

        { passe die OffSets an }
        Inc(Dest, ConcatLen); //Erhöhe den Pointer des Resultats um die Menge der kopierten Chars
        Inc(PAStr, APos); //Erhöhe den Pointer des AStr um APos Stellen
      end;
      Inc(PEnd+APos); //nun inkrementiere PEnd wieder um APos Stellen, welche wir oben abgezogen haben
      { kopiere den Rest oder garnix (welches sich aus der Differenz von PEnd - PAStr ergibt) von AStr ins Resultat }
      System.Move(PAStr^, Dest^, (PEnd - PAStr)* SizeOf(Char));
    end;
  end;
end;
Ich habs jetzt mal Quick & Dirty mit moves verpackt, da er ja Variable Längen und unterschiedliche Positionen zuläßt.
Die moves arbeiten intern auch mit Loops, somit ist es möglich, das diese Variante nicht unbedingt viel schneller ist.
Jedoch nehm ich der großen Loop(char by char) gleich die Luft raus, indem ich den offset auf die fertige String-Länge zurücksetzte. Und auch nicht mehr schauen muß, ob der Delimiter an der richtigen Position ist oder nicht, es ist garantiert!

Nun ist es aber wieder so, daß das Original leicht verstädlich ist... Und meines wieder nicht. Dennoch behaupte ich, diese Version ist der Version von Sir Rufo weit überlegen .... e.g. Pointer-Offsets!

EgonHugeist 28. Jan 2016 14:56

AW: Leerzeichen in String einfügen
 
Liste der Anhänge anzeigen (Anzahl: 1)
@Sir Rufo,

der unangemeldeten Challange halber habe ich den vorherig geposteten Code mal gefixt. Habe mir die 8min genommen es zu testen.
Resultate:

Zitat:

Benchmarking DupeString('xyz', shl^0..10) Iterations: 2000000:
Autor: Sir Rufo Function: StrInsertEveryNthPos TickCount: 140922

Benchmarking DupeString('xyz', shl^0..10) Iterations: 2000000:
Autor: EgonHugeist Function: EH_StrInsertEveryNthPos TickCount: 25938
Auch hier wieder CountOfChar div APos length loop. Da hier alles variabel fallen die Benchmarks auch anders aus.

JFYI, includes the test, cheers.

Edit:
Nur mal so, hier ergibt sich ein irrsinninger Spread: desto größer APos oder AInsertStr desto weiter läuft meine Interpertation der deinen davon.

Habt Spaß beim Selber tüfteln.

Dejan Vu 28. Jan 2016 19:07

AW: Leerzeichen in String einfügen
 
Zitat:

Zitat von himitsu (Beitrag 1328581)
Zitat:

Zitat von Dejan Vu (Beitrag 1328515)
Ich schlage vor, die beste Funktion mit der Parameterübergabeoption 'register' zu versehen, dann kann man nochmal einiges Rauskitzeln.

Das macht Delphi/Pascal standardmäßig von Haus aus.

Echt? Ich hab doch irgendwo eine unverschämt gepimpte Version einer Stringfunktion gesehen, die das Result direkt in ein Register schreibt... Ich dachte, das würde so gehen.

Na ja. Ist eh wurscht.

EgonHugeist 30. Jan 2016 04:33

AW: Leerzeichen in String einfügen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Guten Morgen,

wollte Dejan Vu's produktiven Worten eigentlich den Vortritt beim Abschluß dieses Threads lassen. Doch:

Zitat:

Zitat von EgonHugeist (Beitrag 1328564)
@Dejan Vu
Ich habe hierbei auch etwas gelernt:
Code:
    if (Pointer(Result) = nil) or //result unassigned?
       (PLongInt(NativeUInt(Result) - SizeOf(LongInt))^ <> SrcLen) {PStrRec.Len} or //length different?
       (PLongInt(NativeUInt(Result) - (SizeOf(LongInt) shl 1))^ <> 1) {PStrRec.RefCnt} then //no unique string?
      SetLength(Result,SrcLen+((SrcLen-1) shr 2));
Für hoch performante String functions war ich es gewohnt erst den String-Refcount und die Länge zu testen, bevor ich ein SetLength() calle. Die älteren IDE's haben in jedem Falle einen neuen Unique-String erzeugt. Nun scheint mir das dieser Test schon implizit dem SetLength drin ist. Oder baut das der Compiler neuerdings direkt ein? Das war nicht immer so, und gilt herauszufinden, seit welcher Version sich Delphi so verhält. Klar ich spare den Call aber der Code wird unleserlich und für jemanden, der davon keine Ahnung hat, völlig banane.

Nu kuck ... muß meine gewohnte low-Level Syntax nun doch nicht in Frage stellen. Mir fällt's gerade wie Schuppen von den Augen:
Ich vergleiche hier die Result-Länge mit der Source-Länge. :roll: Na sooo wird dad doch auch nix!

Also ... habe ich die Unit nochmals angehängt. Es kitzelt doch noch einige Ticks raus:

Zitat:

Zitat von Benchmarks
Task: Fuege einen "_" -Char an jeder 4. Stelle ein!
Benchmarking DupeString('xyz', 1 shl^0..10) Iterations: 2000000:

Autor: "Mavarik" Function: "MavarikQuadUnderScoreInjector" TickCount: 9688
Autor: "Dejan Vu" Function: "DejanVuQuadUnderScoreInjector" TickCount: 575078
Autor: "EgonHugeist" Function: "leerzeichen" TickCount: 3500
Autor: "Sir Rufo" Function: "StrInsertEveryNthPos" TickCount: 85328
Autor: "EgonHugeist" Function: "EH_QuadUnderScoreInjectorBy4" TickCount: 3313
Autor: "EgonHugeist" Function: "EH_QuadUnderScoreInjectorBy8" TickCount: 3250

Task: Fuege einen "/\"-String an jeder 4. Stelle ein!
Benchmarking DupeString('xyz', 1 shl^0..10) Iterations: 2000000:

Autor: "Sir Rufo" Function: "StrInsertEveryNthPos" TickCount: 139406
Autor: "EgonHugeist" Function: "EH_StrInsertEveryNthPos" TickCount: 25422

From my POV ... case closed.

PS. @Mavarik das div 4 braucht ca. 10 Zyklen, wärend ein shr 2 einen braucht.. Ist der Hauptunterschied zwischen "Leerzeichen" und "EH_QuadUnderScoreInjectorBy4"..

Luckie 30. Jan 2016 06:11

AW: Leerzeichen in String einfügen
 
Ich habe mir jetzt nicht alle Lösungen angeguckt. Vielleicht ist meine Idee schon dabei: Ausgangszeichenkette in Vierer-Blöcke aufsplitten und beim Zusammensetzen die Leerzeichen einfügen.

Vielleicht auch nicht am schnellsten, aber sehr anschaulich, was passiert, denke ich.

EgonHugeist 30. Jan 2016 06:31

AW: Leerzeichen in String einfügen
 
Hallo Michael,

klingt gut! Wäre schön, wenn du es in Zeilen ausdrückst. Kann nur neue Perspektiven aufzeigen, man lernt nie aus! Würde mich freuen..

Luckie 30. Jan 2016 06:34

AW: Leerzeichen in String einfügen
 
Öhm. Ich weiß gar nicht, ob mein BDS 2006 noch startet oder ob ich da erst Staub putzen muss. :roll:

EgonHugeist 30. Jan 2016 06:42

AW: Leerzeichen in String einfügen
 
Wäre schön, wenn du den Staubwedel holst. :stupid:

Ich hatte einen ähnlichen Ansatz verfolgt, habe ihn wieder nach 10min verworfen, drum würde es mich freuen, wenn du die Zeit findest. Just4Fun

Luckie 30. Jan 2016 06:47

AW: Leerzeichen in String einfügen
 
I'll do my very best, Mrs Sophy Mr Hugeist.

Warum hast du ihn wieder verworfen?

EgonHugeist 30. Jan 2016 07:05

AW: Leerzeichen in String einfügen
 
Cheers Mr Pommeroy! Mr Luckie

Well ... das genaue aufteilen in die 4er Teile des Strings und deren Positions-Alignments haben mir zu lange gedauert.

Da der String "xyz" oder "1234567890", riesßig, oder, oder sein kann, waren die langsamen Modulo's für das Alignen der PChars gefragt etc.
Wäh that kills a cat! (Er trinkt aus der Blumenvase)
And last but not least -> Mein code wäre vom Style wieder für den unerfahrenen nicht zum Verstehen gewesen. Also hab ich's bei den 3 Versionen belassen.

Vielleicht hab ich mich auch einfach zu dusselig angestellt. K.A. drum mach einfach mal, laß dich nicht beeinflußen, wenn du die Zeit findest.

Luckie 30. Jan 2016 07:15

AW: Leerzeichen in String einfügen
 
Ich hatte jetzt keine allgemeine Lösung im Kopf. Ich wäre von 128 Zeichen ausgegangen, wie es für den Fall gefordert ist. Diese in ein Array von 32 Strings kopieren. (Das dürfte am aufwendigsten sein.) Dann einfach in einer Schleife durch das Array iterieren und mit Leerzeichen zwischen den Array-Elementen wieder zusammensetzen. Nach dem Motto: "Same function as every year, Luckie!"

EgonHugeist 30. Jan 2016 07:22

AW: Leerzeichen in String einfügen
 
Nun gut. So wie ich den TE verstehe, kann der String !max! 128 Zeichen lang sein.

Wäre also, wie Sir Rufo's Code eine neue Kategorie für das einfügen.
Mach sie auf(in meiner Unit), füge einen neuen Test hinzu, der davon ausgeht und los geht's. Da hätte ich auch sofort 'ne fast Version im Kopf.

Wollen wir?

Luckie 30. Jan 2016 07:27

AW: Leerzeichen in String einfügen
 
Das wird vor heute Abend nichts mehr. Ist deine Unit BDS2006 kompatibel?

EgonHugeist 30. Jan 2016 07:38

AW: Leerzeichen in String einfügen
 
Denke schon, drum hab ich die Unicode defines mit reingemacht. Also dann bis später...

Hab's fertsch! Habe die Wiederholung auf 32000000 gedreht...

Code hänge ich an, wenn du oder ein anderer soweit ist:
Zitat:

Zitat von Benchmark
Task: Fuege einen "_" -Char an jeder 4. Stelle eines 128 Zeichen langen Strings ein!
Benchmarking DupeString('1234', 1 shl 5) Iterations: 32000000:

Autor: "EgonHugeist" Function: "EH_QuadUnderScoreInsertFix128String" TickCount: ?????


EgonHugeist 30. Jan 2016 08:09

AW: Leerzeichen in String einfügen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hänge dir mal den zusätzlichen Test bei.

Siehe ganz unten Test128;

Dann brauchst du nicht erst den Test schreiben. Cheers


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:59 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz