Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Einen Komma-Text richtig trennen. (https://www.delphipraxis.net/108490-einen-komma-text-richtig-trennen.html)

gunfran 14. Feb 2008 17:44


Einen Komma-Text richtig trennen.
 
Hallo liebe Delphi-Praxis Mitglieder

Ich habe ein kleines Problem, wo ich mal wieder eure Hilfe brauche. Ich will einen String in ein bestimmtes Format bekommen. Der String könnte z.B. so in die Funktion reinkommen.

Zitat:

BORKUM{61}, BLA2{60}, REL{62}, EN/NORD{72}, ESSEN{59}, TRINKEN{70}, HERNE{71}, HSK1{67}, MAMA123{65}, KW/DINSL{64}, OBERHAUSEN{66}, EN/SÜD{73}, KW/MOERS{63}, HSK2{68}, HSK3{69}
Folgende Funktion habe ich dafür vorgefunden. Was ich erreichen will, ist das der String, der am Ende rauskommt auch damit zurecht kommt, wenn in dem Namen vor der geschweiften Klammer auch evtl ein Komma oder ein Leerzeichen vorkommt. Also das z.b. der Input ESS,EN{59}, TRIN KEN{70} am Ende ESS,EN, TRIN KEN ergibt.

Ist das mit einfachen Mitteln möglich? Mir fehlt dafür leider ordentlich Basiswissen von Delphi.

Ach ja, wichtige Information, ich arbeite hier mit Delphi 7 Professional.

Schon mal vielen Dank im voraus und nun folgt der bisherige Code, der zwar ansich gut funktioniert aber mit Kommas und Leerzeichen im Namen nicht zurecht kommt.

Gruß Michael

Delphi-Quellcode:
function getSender(List: Boolean; Value: String): String;
(* Wandelt einen String mit SenderId in eine Senderliste oder
   einen kommagetrennen SenderSting ohne SenderId *)

Delphi-Quellcode:
function getSender(List: Boolean; Value: String): String;
var Sl : TStringlist;
    S : String;
    i : Integer;
begin
 Sl := TStringlist.Create;
 sl.Text := Value;
 Result := '';
 if sl.Count > 0 then
 begin
  S := Sl[0]; // Falls Text mehrzeilig
    sl.CommaText := S;
  for i := sl.Count -1 downto 0 do
   if pos('{', Sl[i]) > 0 then begin
    Sl[i] := CopyBis('{', SL[i]);
   end
   else sl.Delete(i);
  if List then Result := Sl.Text
  else begin
   Result := sl[0];
   for i := 1 to sl.Count -1 do Result := Result + ', ' + Sl[i];
  end;
 end;
end;

Namenloser 14. Feb 2008 17:57

Re: Einen Komma-Text richtig trennen.
 
Was ist, wenn du nach "," einfach nach "}," suchst? Würde das dein Problem lösen?

bluesbear 14. Feb 2008 18:07

Re: Einen Komma-Text richtig trennen.
 
Also mit einer TStringList klappt das schon mal nicht, die trennt nach jedem Komma.
Da muss man den String von Hand zerlegen.

Beim ersten Wort mit Pos nach einem '{' suchen, mit Copy bis zu dieser Position dieses Wort auslesen.
Dann mit Pos nach einem ',' suchen, und mit Delete den String bis zu dieser Position links abschneiden. Mit Trim evtl. führende Leerzeichen löschen, und dann weiter wie beim ersten Wort.

Dax 14. Feb 2008 18:13

Re: Einen Komma-Text richtig trennen.
 
Wie wär es denn mit Regexen?
Code:
([^{]+)(?={\d+},)

omata 14. Feb 2008 18:16

Re: Einen Komma-Text richtig trennen.
 
Vielleicht so...

Delphi-Quellcode:
function MyFunc(input:string):string;
var RegExpr:TRegExpr;
begin
  RegExpr:=TRegExpr.Create;
  try
    RegExpr.ModifierG:=false;
    RegExpr.Expression:='{[0-9]*}';
    Result:=RegExpr.Replace(input, '', true);
  finally
    RegExpr.Free;
  end;
end;
RegExpr

Gruss
Thorsten

r2c2 14. Feb 2008 18:30

Re: Einen Komma-Text richtig trennen.
 
Zitat:

Zitat von gunfran
Mir fehlt dafür leider ordentlich Basiswissen von Delphi.

Das kann man ändern:
http://r2c2.weingut-rehn.de/content3...mit_Delphi.htm

mfg

Christian

bluesbear 14. Feb 2008 18:31

Re: Einen Komma-Text richtig trennen.
 
Regular Expressions sind natürlich viel eleganter! :-D
Gleich mal gucken gehen, ich bin begeistert!
Ich bin leider teilweise geistig noch auf dem Stand von Delphi3, berufsbedingt...

gunfran 15. Feb 2008 10:53

Re: Einen Komma-Text richtig trennen.
 
Das mit der Regular Expression-Geschichte wirkt interessant. Ich probier das mal aus. Bis hierher erstmal vielen Dank für die Hilfe. Ich schreib mal, wie weit ich damit gekommen bin.

Gruß

Michael

Xong 15. Feb 2008 11:17

Re: Einen Komma-Text richtig trennen.
 
Zitat:

Zitat von bluesbear
Regular Expressions sind natürlich viel eleganter! :-D

Und langsamer!
Z.B. bei Webanwendungen, die mit einer hohen Besucheranzahl fertig werden müssen, sollte man "normale" Stringverarbeitungsfunktionen immer regulären Ausdrücken vorziehen!

Reguläre Ausdrücke werden nur bei komplexen Aufgaben benötigt, bei denen sich der Programmieraufwand nicht lohnt bzw. zu groß wird.

LG,
Xong

PS: Natürlich ist das Problem bei reinen Single-User-Anwendungen nicht gegeben.

SirThornberry 15. Feb 2008 11:47

Re: Einen Komma-Text richtig trennen.
 
in der Codelib gibt es einige Funktionen welche dir den String auch an "}," trennen können.

angos 15. Feb 2008 12:21

Re: Einen Komma-Text richtig trennen.
 
Hi,

folgende Funktion dürfte erledigen was du brauchst:

Delphi-Quellcode:

function TrenneText(sText, sDelim1, sDelim2, sDelimNew: String): String;
var
  iPos1, iPos2: Integer;
begin
  Result := '';
  iPos1 := pos(sDelim1, sText);
  iPos2 := pos(sDelim2, sText);
  while ((iPos1 > 0) and (iPos2 > 0)) do
  begin
    Result := Result + copy(sText, 1, iPos1-1) + sDelimNew;
    sText := copy(sText, iPos2 + Length(sDelim2), Length(sText));
    iPos1 := pos(sDelim1, sText);
    iPos2 := pos(sDelim2, sText);
  end;
end;

// aufruf in deinem Fall mit
TrenneText('BORKUM{61}, BLA2{60}, REL{62}, EN/NORD{72}, ESSEN{59}, TRIN,KEN{70}, HERNE{71},
  HSK1{67}, MAMA123{65}, KW/DINSL{64}, OBERHAUSEN{66}, EN/SÜD{73}, KW/MOERS{63},
  HSK2{68}, HSK3{69}'
  , '{', '},', ',');

SirThornberry 15. Feb 2008 13:34

Re: Einen Komma-Text richtig trennen.
 
autsch, bitte nicht die funktion verwenden. Dein Programm wird es dir auf längere sicht danken.
Durch
Delphi-Quellcode:
Stringx := Stringx + irgendwas
wird die Länge von Stringx immer wieder verändert, somit immer wieder neuer speicher angefordert und der alte umkopiert und bei einigen Speichermangern ist der Speicher danach derart fragmentiert das du probleme bekommen kannst wenn du wieder speicher anforderst.

schau dir mal das hier an: http://www.delphipraxis.net/internal...=205244#205244

gunfran 15. Feb 2008 14:15

Re: Einen Komma-Text richtig trennen.
 
Ich hab grad das Problem grad mit dieser Regular Expression hinbekommen und war schon sehr angetan. Das werde ich mir mal genauer angucken, ob man die in Zukunft nicht häufiger mal gebrauchen kann. Trotzdem mal aber besten Dank bezüglich der Performance. Im Moment ist dies allerdings kein Problem, aber falls das in Zukunft mal der Fall sein wird, werd ich das im Hinterkopf behalten.


Ach ja. Ihr seid spitze.

Xong 15. Feb 2008 14:19

Re: Einen Komma-Text richtig trennen.
 
Zitat:

Zitat von SirThornberry
Durch
Delphi-Quellcode:
Stringx := Stringx + irgendwas
wird die Länge von Stringx immer wieder verändert, somit immer wieder neuer speicher angefordert und der alte umkopiert [...]

Sicher?
Jeder gute Compiler (mit dem ich mich auskenne) versucht einen String zu vergrößern, indem er er den Speicherplatz einfach vergrößert/verlängert. Erst wenn dies nicht klappt, wird ein vollkommen neuer Speicherplatz vergeben und der alte aufgelöst. Das hat C schon so gemacht und es würde mich wundern, wenn es in Delphi anders wäre.

SirThornberry 15. Feb 2008 15:53

Re: Einen Komma-Text richtig trennen.
 
ich bin mir da ganz sicher. Mach einfach mal paar Performancetests und du wirst das erschreckende Ergebnis sehen.
Bei früheren Programmen konnte ich das ständige Vergrößern von Strings als Performancekiller Nummer eins ausmachen und wenne in Programm das ständig macht und einige Stunden durchläuft bekommt man schnell mal ein "out of memory".

Das man angeforderten Speicher einfach vergrößern kann war mir neu. Aber wie dem auch ist, meine Tests haben bisher ergeben das ein ständiges vergrößern von Arrays, Strings etc. zu stargen Performanceeinbrüchen führt.
Bist du dir sicher das C das schon gemacht hat? In C sind mir strings bisher noch gar nicht begegnet (was aber vielleicht auch an der minimalen Bibliothek bei der Microcontrollerprogrammierung liegt)

Xong 15. Feb 2008 16:31

Re: Einen Komma-Text richtig trennen.
 
In C gibt es ja auch keine Stringverarbeitung. =)
Dafür gibt es die Standardbibliotheken, in denen Stringfunktionen bereitgestellt werden. So erreicht man die Plattformunabhängigkeit von C (d.h. die Stringfunktionen sind betriebssystemspezifisch deklariert).

Es gibt in C eine Funktion, deren Name mir gerade nicht einfällt. Mit der ist genau das möglich, was ich beschrieben habe. Es kann natürlich sein, dass der Delphi-Compiler das anders handhabt. Keine Ahnung. :stupid: Ich dachte ja nur... Alles andere wäre so ineffizient. Aber Ineffizienz ist schließlich auch der Preis für Bequemlichkeit, nicht wahr?!

LG,
Xong

marabu 15. Feb 2008 21:32

Re: Einen Komma-Text richtig trennen.
 
Hallo,

in Delphi sorgt die Prozedur ReallocMem() für die Vergrößerung eines bereits angeforderten Speicherblocks. Ist der Speicher hinter dem aktuellen Block in Benutzung, dann wird der aktuelle Block freigegeben und der größere Speicher an anderer Stelle zugeordnet.

Der Reiz einer Regular Expression liegt für mich im nicht prozeduralen Ansatz, aber sie kann nie schneller sein, als eine gute handkodierte Lösung:

Delphi-Quellcode:
function PurgeId(const list: string): string;
var
  iPos, iDest: Integer;
  skipping: Boolean;
begin
  skipping := False;
  SetLength(Result, Length(list));
  iDest := 1;
  for iPos := 1 to Length(list) do
    if skipping then
      skipping := list[iPos] <> '}'
    else if list[iPos] = '{' then
      skipping := True else
      begin
        Result[iDest] := list[iPos];
        Inc(iDest);
      end;
  SetLength(Result, Pred(iDest));
end;
Freundliche Grüße

alzaimar 15. Feb 2008 23:25

Re: Einen Komma-Text richtig trennen.
 
Zitat:

Zitat von marabu
Der Reiz einer Regular Expression liegt für mich im nicht prozeduralen Ansatz, aber sie kann nie schneller sein, als eine gute handkodierte Lösung:

... deren Performance durch Einbeziehung egozentrischer Performancemanie noch leicht gesteigert werden kann :stupid: :
Delphi-Quellcode:
Function AlzPurgeID(Const list: String): String;
Var
  iStop, iPos, iDest: Integer;

Begin
  iStop := Length(list);
  SetLength(Result, iStop);
  iDest := 0;
  iPos := 1;
  While iPos <= iStop Do Begin
    If list[iPos] = '{' Then
      While (iPos <= iStop) And (list[iPos] <> '}') Do
   inc(iPos)
    Else Begin
      Inc(iDest);
      Result[iDest] := list[iPos];
    End;
    inc(iPos);
  End;
  SetLength(Result, iDest);
End;
Sir Thornberry's Anmerkungen zur Performancebremse 'sString := sString + sSubString' kann ich nur beipflichten. Der Unterschied ist in etwa vergleichbar miz dem Unterschied in der Zubereitungszeit einer Tasse Nescafe und dem eigenhändigen Anbau, Ernte, Röstung, Malen und Brühen von jamiakanischem Blue Mountain. Wobei der Vergleich hinkt: Jamaican Blue Mountain ist es Wert, etwas länger zu warten, Stringkonkatenation hingegen nicht.

Und nun: Assemblerfraktion und Performancegeeks vortreten, bitte!

grenzgaenger 16. Feb 2008 01:00

Re: Einen Komma-Text richtig trennen.
 
Zitat:

Zitat von Xong
Zitat:

Zitat von SirThornberry
Durch
Delphi-Quellcode:
Stringx := Stringx + irgendwas
wird die Länge von Stringx immer wieder verändert, somit immer wieder neuer speicher angefordert und der alte umkopiert [...]

Sicher?
Jeder gute Compiler (mit dem ich mich auskenne) versucht einen String zu vergrößern, indem er er den Speicherplatz einfach vergrößert/verlängert. Erst wenn dies nicht klappt, wird ein vollkommen neuer Speicherplatz vergeben und der alte aufgelöst. Das hat C schon so gemacht und es würde mich wundern, wenn es in Delphi anders wäre.

yep, sicher! was soll der gute compieler auch machen, wenn er keinen speicher mehr hat... tja, er muss halt 'n neuen anfordern und dann die daten dort reinkopieren... beim nächsten mal, hat er dann wieder keinen speicher, alles ist zu klein, zu eng... und dann muss er wieder speicher anfordern.... so ist dies auch in C nicht nur in delphi...

tja, und C hat keine strings... sind halt nur arrays of char... (nachbau in delphi PCHAR :-) )

angos 2. Apr 2008 16:28

Re: Einen Komma-Text richtig trennen.
 
Zitat:

Zitat von SirThornberry
autsch, bitte nicht die funktion verwenden. Dein Programm wird es dir auf längere sicht danken.
Durch
Delphi-Quellcode:
Stringx := Stringx + irgendwas
wird die Länge von Stringx immer wieder verändert, somit immer wieder neuer speicher angefordert und der alte umkopiert und bei einigen Speichermangern ist der Speicher danach derart fragmentiert das du probleme bekommen kannst wenn du wieder speicher anforderst.

schau dir mal das hier an: http://www.delphipraxis.net/internal...=205244#205244

Ist zwar schon ein bisschen her, aber wow :shock: . Ich wusste, dass meine Funktion nicht die schnellste ist, aber dass das ein so gravierender Unterschied ist, hätte ich jetzt nicht gedacht. Bei knapp 500.000 Zeilen braucht mein Code auf meinem Rechner 11875 Millisekunden. Da gegenüber braucht der letzte von alzaimar gepostete Code nur 16 Millisekunden. Na da hab ich wohl wieder etwas gelernt.

Vielen Dank :dp:

Gruß

TERWI 2. Apr 2008 16:35

Re: Einen Komma-Text richtig trennen.
 
Ein wenig TERWI-Senf dazu...
Diese Funktion nutze ich schon seit ner kleinen Ewigkeit, um Strings - z.B. durch Komma oder andere Zeichen getrennt - zu zerlegen.
Kann man dann logo auch rekursiv auf die Ergebnisse anwenden ...
Delphi-Quellcode:
function SplitStr(T : char; var S : string) : string;
var
  p : integer;
begin
  Result := S;                       // Result ist zunächst S unverändert !
  if s = '' then exit;               // ... da gibts nix zu trennen
  p := Pos(T, S);                    // Position des Trennzeichens 'T' ermitteln
  if p > 1 then                      // Trennzeichen ist vorhanden !
  begin                              // > JA
    Result := trim(Copy(S,1,p-1));   // Bis zum Trennzeichen aus S nach Result kopieren (links)
    S := trim(Copy(S,p+1,Length(S))); // Rest nach Trennz. in S zurückgeben (rechts)
  end
  else S := '';                      // Kein Trenner - Result (links) ist S und S (rechts) ist leer
end;
Da würde ich gunfran's Beispiel erst mal grob nach Kommata zerlegen
Und dann weiter den Wert in {} ermitteln... Nur ne grobe Idee, nicht getestet !
Delphi-Quellcode:
...
  s_org := 'BORKUM{61}, BLA2{60}, REL{62}, EN/NORD{72}, ESSEN{59}, TRINKEN{70}, HERNE{71}, HSK1{67}, MAMA123{65}, KW/DINSL{64}, OBERHAUSEN{66}, EN/SÜD{73}, KW/MOERS{63}, HSK2{68}, HSK3{69}';
  repeat
    s_result := SplitStr(',', s_org);
    s_rest := s_result; // Edit: ... sonst wird das nix mit repeat until.
    // s_result prüfen... entweder leer oder was gültiges vor dem ','
    // ggf. noch mal ein SplitStr('/', s_result) darauf um für ein '/' zu trennen.... Achtung: s_result wird verändert !
    s_temp := SplitStr('{',s_result);      // die {-Klammer vorne weg und den Rest erhalten
    // mach was mit s_temp vor dem {
    SetLength(s_result, Length(s_result - 1)); // die }Klammer hinten weg --- EDIT: Korrgiert...
    // mach hier was mit s_result
  until s_rest = '';
  // Edit: oder until (Pos(',', s_org) < 1);
Idee ohne Gewehr zum selber selbsterschiessen / weiterdenken... :spin:

PS: Ich bin da nicht so der Performance-Kasper. Sollte logo schon zügig gehen... Aber mit der SplitStr-Func habe ich schon relativ dicke Daten im xx-MB-Format durchwurstet und ich würde mach dumpf behaupten, das da die Platte (von der gelesen wurde) eher das langsamste Teil in der Kette war...

DP-Maintenance 2. Apr 2008 16:48

DP-Maintenance
 
Dieses Thema wurde von "Matze" von "Programmieren allgemein" nach "Sonstige Fragen zu Delphi" verschoben.
Delphi-Frage

grenzgaenger 2. Apr 2008 23:45

Re: Einen Komma-Text richtig trennen.
 
und hast dir das auch schon mal angesehen? müsst eigentlich ziemlich genau deinen bedarf treffen...

alzaimar 3. Apr 2008 07:58

Re: Einen Komma-Text richtig trennen.
 
Zitat:

Zitat von TERWI
und ich würde mach dumpf behaupten, das da die Platte (von der gelesen wurde) eher das langsamste Teil in der Kette war...

Bestimmt, nur wenn die Daten schon im Speicher sind oder per TCPStream reintrudeln, möchte man im Server keine unnötigen CPU-Zyklen, denn wenn viele Threads gleichzeitig rumsplitten, dann geht der Server -pardauz- in die Knie. Insofern muss man immer nach möglichst effizienten Verfahren suchen. Dein Verfahren ist sehr aufwändig, denn es wird ständig unwichtiges Zeugs hin-und-her kopiert.

Hansa 3. Apr 2008 13:25

Re: Einen Komma-Text richtig trennen.
 
Das Wort "feste Feldlänge" ist noch nicht gefallen. Damit sind Trennzeichen-Probleme ein für allemal aus der Welt geschafft. Selbst dann wenn ein DAU "Herr M;ller" als Name gespeichert hat. Das Komma selber ist wegen Dezimalzahlen sowieso auszuschließen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:16 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