Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Effiziente Methode, einen String mittels Delimiter zu splitten (https://www.delphipraxis.net/195958-effiziente-methode-einen-string-mittels-delimiter-zu-splitten.html)

Codehunter 11. Apr 2018 09:14

Delphi-Version: 10.2 Tokyo

Effiziente Methode, einen String mittels Delimiter zu splitten
 
Hallo!

Ich kenne mittlerweile ein halbes Dutzend Methoden, einen String anhand eines Delimiter zu splitten. Die meisten arbeiten mit TStringList. Entweder mit DelimitedText, was aber den Nachteil hat dass man nur ein Zeichen (Char) als Delimiter einsetzen kann. Oder mittels
Delphi-Quellcode:
SL.Text:= StringReplace(TheString, TheDelimiter, sLineBreak, [rfReplaceAll]);
Teilweise habe ich auch schon gesehen, den String mit einer Runner-Schleife zu durchlaufen, Memcopy je Zeichen in einen zweiten String zu machen und beim Auffinden eines Delimiter den zweiten String in eine Stringliste zu adden. Davon gibt es auch noch eine Variante, einen String als PChar anzusprechen, den Zeiger zu schubsen, Memcopy direkt auf StringList.Text zu machen und gefundene Delimiter durch sLineBreak zu ersetzen.

Nur frage ich mich, wie effizient ist denn diese ganze "Schleiferei"? Die meisten dieser Codeschnipsel sind 10 Jahre und älter. Gibt es vielleicht inzwischen in der RTL mitgeliefert schon eine Art Äquivalent zu der explode()-Funktion in PHP, die z.B. ein TStringDynArray auswirft?

Grüße
Cody

EDIT: PS: Schön wäre die Möglichkeit, als Delimiter mehr als ein Zeichen (Char) verwenden zu können.

günni0 11. Apr 2018 09:16

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
Suchst du sowas?

Delphi-Quellcode:
function Explode(const ADelimiter, AString: string): TArray<string>;
begin
 Result := AString.Split([ADelimiter]);
end;

StrOut := Explode(':;', StrIn);

Neutral General 11. Apr 2018 09:17

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
In den neueren Versionen gibt es s.Split (s ist ein String).

Codehunter 11. Apr 2018 09:26

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
Ha, dacht ichs mir doch dass es inzwischen was generisches ab Werk gibt :-) Und dann auch noch so schön flexibel. Schade nur dass die Dokumentation dazu so dünne ist.

Uwe Raabe 11. Apr 2018 09:31

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
Die Funktion SplitString gibt es in StrUtils schon seit D2010.

Codehunter 11. Apr 2018 09:37

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
Ich schätze mal dass dies einer dieser Fälle ist, wo das Internet voll ist mit wieder und wieder kopierten und modifizierten Varianten, die aus grauer Ansistring-Vorzeit stammen. Lässt man nämlich - mangels Kenntnis dessen - das Keyword "Split" weg oder verwendet stattdessen "explode" als Suchbegriff, findet man nur die altertümlichen Schleifenlösungen.

Neutral General 11. Apr 2018 09:49

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
Zitat:

Zitat von Codehunter (Beitrag 1398712)
Ha, dacht ichs mir doch dass es inzwischen was generisches ab Werk gibt :-)

Nur als kleiner Hinweis: An der Methode ist nichts "generisch" ;)
Zumindest nicht in dem Sinn wie "generisch" in Delphi bzw. generell in Programmiersprachen benutzt wird.

Codehunter 11. Apr 2018 09:53

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
Der Ergebnistyp ist generisch :-) Mehr meinte ich damit eigentlich gar nicht.

KodeZwerg 11. Apr 2018 10:07

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
Hier ein Mini Beispiel wie man es machen könnte:
Delphi-Quellcode:
procedure MySplit (const Delimiter: Char; Input: string; const Strings: TStrings);
begin
  Assert(Assigned(Strings));
  Strings.Clear;
  Strings.Delimiter := Delimiter;
  Strings.DelimitedText := Input;
end;


// Aufruf:
procedure TForm1.Button1Click(Sender: TObject);
var
  SL: TStringList;
begin
  SL := TStringList.Create;
  try
    MySplit(' ', 'Hallo Delphi Praxis', SL);
    ShowMessage(SL[0]); // = Hallo
    ShowMessage(SL[1]); // = Delphi
    ShowMessage(SL[2]); // = Praxis
  finally
    SL.Free;
  end;
end;
Meintest Du so etwas?

Daniel 11. Apr 2018 10:18

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
Du hast den Eingangsbeitrag gelesen?
Zitat:

Zitat von Codehunter (Beitrag 1398707)
Ich kenne mittlerweile ein halbes Dutzend Methoden, einen String anhand eines Delimiter zu splitten. Die meisten arbeiten mit TStringList. Entweder mit DelimitedText, [...]


Harry Stahl 19. Aug 2018 22:24

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
Ich war gerade auch auf der Suche danach, einen String zu splitten und einen Rückgabewert zu erhalten (für eine bestimmte Position im String), mittels einer Standard-Funktion in Delphi, um nicht immer direkt meine eigenen Units einbinden zu müssen, wenn man mal nur einen kleinen Demo-source zeigen möchte.

SplitString hatte ich dann in StrUtils gefunden, aber hier im Forum nochmal interessehalber mal nach "Splitstring" gesucht.

Und siehe da, String.Split ist natürlich noch viel schöner und außerdem schon in System.Sysutils drin, die automatisch eingebunden wird, wenn man eine neue Form anlegt.

Damit kann man das elegant so machen:

Delphi-Quellcode:
procedure TF_Main.Button1Click(Sender: TObject);
var
  s, Part: string;
begin
  s := '#Müller#Hans#Bonn';

  // bisher "GetFieldStr" aus meiner eigenen Unit
  // ShowMessage (GetFieldStr ('#', S, 2); // Müller, Zähung 1-basiert

  ShowMessage (Splitstring (S, '#')[1]); //Müller, Zählung 0-basiert

  // Noch kürzer geht es so
  ShowMessage (S.Split(['#'])[3]); // Bonn
end;
Etwas schade ist zwar, dass ein dynamisches Array für alle Teilstrings erzeugt wird, da ich eigentlich nur einen Eintrag brauche, aber wie gesagt, brauche keine extra Unit und wenn es nicht auf Performance ankommt, bzw. ein Demo zu gestalten, ohne Drittfunktionen zu brauchen, dann geht das schon mal so.

Codehunter 20. Aug 2018 06:32

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
Zitat:

Zitat von Harry Stahl (Beitrag 1411105)
Etwas schade ist zwar, dass ein dynamisches Array für alle Teilstrings erzeugt wird, da ich eigentlich nur einen Eintrag brauche

In dem Fall wäre eine Regular Expression vielleicht besser geeignet?

himitsu 20. Aug 2018 19:11

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
Und natürlich geht ohne Prüfung vor Zugriff sowas nicht, wenn es zu wenige Teilstrings gibt.
Aber hier könnte man auch einfach dafür sorgen, dass die Anzahl immer stimmt.
Delphi-Quellcode:
ShowMessage((S + '###').Split(['#'])[3]);


"Effizient" meint hier also schöner "kurzer" Code und wenige/keine externen Abhängigkeiten?

Codehunter 20. Aug 2018 19:40

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
Zitat:

Zitat von himitsu (Beitrag 1411141)
Delphi-Quellcode:
ShowMessage((S + '###').Split(['#'])[3]);

Kürze und Schönheit müssen nicht gleichbedeutend sein. Ich wühle mich gerade an der Arbeit durch Code nach dem Prinzip "Effizienz durch Kürze". Die Eleganz und Wartbarkeit bewegt sich dabei irgendwo zwischen Assembler und Brainfuck. Die ein oder andere "sprechende" Variable mehr nehme ich jedenfalls dankbar an :-)

Harry Stahl 20. Aug 2018 20:24

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
Zitat:

Zitat von himitsu (Beitrag 1411141)
Und natürlich geht ohne Prüfung vor Zugriff sowas nicht, wenn es zu wenige Teilstrings gibt.
Aber hier könnte man auch einfach dafür sorgen, dass die Anzahl immer stimmt.
Delphi-Quellcode:
ShowMessage((S + '###').Split(['#'])[3]);


"Effizient" meint hier also schöner "kurzer" Code und wenige/keine externen Abhängigkeiten?

Mir ging es nicht um Schönheit, sondern nur um wenige/keine externen Abhängigkeiten.

Wenn ich ein lauffähiges Beispiel liefern möchte, für das der Anwender mit den Delphi-Standard-Units auskommen soll, dann wäre s.split also ein Ersatz für das, was ich sonst verwende (meine sonst verwendete GetFieldStr-Funktion hat natürlich verschiedene Absicherungen und liefert auch das richtige zurück, wenn weniger Felder als vermutet da).

Aber ansonsten: Natürlich kann ich auf Prüfung vor Zugriff verzichten, wenn ich definitiv weiß, dass der String mindestens die angeforderte Anzahl von Teilstrings enthält.

Codehunter 24. Aug 2018 08:31

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
So dumm ist das gar nicht :-) Bisher habe ich das immer mit Stringlisten gelöst und nach dem Splitten mit if Count >= Mindestanzahl geprüft.

Andererseits ist das auch wieder fallabhängig. Denn durch das Sicherstellen von einer Mindestanzahl nimmt man sich unter Umständen die Möglichkeit, Eingabefehler zu prüfen.

Kommt also immer auf den konkreten Einsatzzweck an.

dummzeuch 24. Aug 2018 09:11

AW: Effiziente Methode, einen String mittels Delimiter zu splitten
 
Zitat:

Zitat von Codehunter (Beitrag 1411111)
Zitat:

Zitat von Harry Stahl (Beitrag 1411105)
Etwas schade ist zwar, dass ein dynamisches Array für alle Teilstrings erzeugt wird, da ich eigentlich nur einen Eintrag brauche

In dem Fall wäre eine Regular Expression vielleicht besser geeignet?

Kurze Antwort: Nein.

Lange Antwort: Lineare Ausdrücke korrekt zu erstellen ist ein großer Aufwand, wenn man sowas nicht täglich macht. Es reicht, wenn man es ein-/zweimal falsch macht und nach dem Fehler sucht, um jeglichen Vorteil aufzuwiegen.

Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems..


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:01 Uhr.

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