Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Problem mit procedure Split() (https://www.delphipraxis.net/160107-problem-mit-procedure-split.html)

uragan 27. Apr 2011 20:20

Delphi-Version: 5

Problem mit procedure Split()
 
Hallo

Ich hoffe ich bin hier richtig.
Ich hab ein kleines problem mit der Funktion Split()

was ist den hier falsch?, wieso bekomme ich das ganze nicht gesplittet?

Delphi-Quellcode:
program uragan;

var
list: TStringList;
s : string;
i : integer;

procedure Split(const Delimiter: Char; Input: string; const Strings: TStrings);
begin
   Strings.Clear;
   Strings.Delimiter := Delimiter;
   Strings.DelimitedText := Input;
end;



begin
list := TStringList.create;
s := 'blabla' + HStr('00') + 'blabla2' + HStr('00') + 'blabla3' + HStr('00') + 'blabla4' + HStr('00') + 'blabla5' + HStr('00') ;
Split(HStr('00'), s, list);
for i := 0 to list.count-1 do begin
ShowMessage(list[i]);
end;

end.

mkinzler 27. Apr 2011 20:30

AW: Problem mit procedure Split()
 
Was kommt den raus?

Klaus01 27. Apr 2011 20:38

AW: Problem mit procedure Split()
 
Guten Abend,

was macht denn HStr('00')?
Ist es das gleiche wie #0?

Warum sind Strings in der Paramterliste der Prozedur split als const deklariert?

Grüße
Klaus

EWeiss 27. Apr 2011 21:35

AW: Problem mit procedure Split()
 
changed..

gruss

uragan 27. Apr 2011 21:45

AW: Problem mit procedure Split()
 
Zitat:

Zitat von mkinzler (Beitrag 1097270)
Was kommt den raus?

Es kommen 2 arrays

array0 = blabla
array1 = ?? ist frei, wahrscheinlich #0
mehr kommt nicht

wenn ich Split string ändere, zb auf ","dann klappt es, es muss aber HStr('00')bzw #0 sein

ConnorMcLeod 28. Apr 2011 04:13

AW: Problem mit procedure Split()
 
Hallo,

es kommen nicht *zwei Arrays*, sondern zwei Einträge in einer TStringList. Einer gleicht 'blabla' und einer ist ein Leerstring.

Mach einen Breakpoint auf
Strings.DelimitedText := Input;
und steppe mal mit F7 durch. Dann wird Dir klar, was passiert. Kurz gesagt: #0 geht halt nicht.

Antwort1) der Delimiter darf bei dieser Vorgehensweise nicht #0 sein.
Antwort2) eine TStringList für diesen Zweck zu verwenden ist super praktisch und super Performance fressend.

Mir hat eine Funktion auf Stackoverflow ganz gut gefallen:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
const
  MYDELIMITER = #0;
var
  s  : string;
  sTok: string;
  i  : integer;

  function GetTok(const Line: string; const Delim: Char; const TokenNum: Byte): string;
  { LK Nov 8, 2009 - Reoptimized using PChars instead of calls to Pos and PosEx }
  { See; http://stackoverflow.com/questions/1694001/is-there-a-fast-gettoken-routine-for-delphi }
  var
    I, CurToken: Integer;
    PLine, PStart: PChar;
  begin
    CurToken := 1;
    PLine := PChar(Line);
    PStart := PLine;
    for I := 1 to length(Line) do begin
      if PLine^ = Delim then begin
        if CurToken = TokenNum then
          break
        else begin
          CurToken := CurToken + 1;
          inc(PLine);
          PStart := PLine;
        end;
      end
      else
        inc(PLine);
    end;
    if CurToken = TokenNum then
      SetString(Result, PStart, PLine - PStart)
    else
      Result := '';
  end;

begin
  s := 'blabla' + MYDELIMITER + 'blabla2' + MYDELIMITER + 'blabla3' + MYDELIMITER + 'blabla4' + MYDELIMITER + 'blabla5' + MYDELIMITER ;

  i := 1;
  sTok := GetTok(s, MYDELIMITER, i);
  while ('' <> sTok) do
  begin
    ShowMessage(sTok);
    inc(i);
    sTok := GetTok(s, MYDELIMITER, i);
  end;
end;
HTH

FredlFesl 28. Apr 2011 06:56

AW: Problem mit procedure Split()
 
Deine Funktion kommt nur mit kurzen Strings klar und ist vom Aufwand O(n^2), weil für jedes Token immer von Anfang an gesucht wird. Ob das Schneller ist, bezweifle ich mal ganz stark.
Im Gegensatz dazu ist die TStringList-Geschichte sehr viel mächtiger, denn sie kommt mit allen Stringtypen und mit in Gänsefüschen eingeschlossenen Texten klar, z.B. wird
Delphi-Quellcode:
a,"b,c",d
in drei Strings ("a", "b,c" und "d") aufgeteilt.

Der Code von TStringlist sieht auch ganz schön flott aus.

Klaus01 28. Apr 2011 07:38

AW: Problem mit procedure Split()
 
..alternativ könntest Du auch mal diese Explode-Prozedur oder diese explode Funktion testen.

Grüße
Klaus

himitsu 28. Apr 2011 07:52

AW: Problem mit procedure Split()
 
Wer eine Stringliste als Splitter nutzt, der sollte sich von #0 als Trenner verabschieden.
Alles, was intern PChar nutzt oder eine Kompatibilität zu diesem bietet, das kann nich genutzt werden.

#0 = Textende

also weiter macht die Stringliste auch nicht

mkinzler 28. Apr 2011 08:24

AW: Problem mit procedure Split()
 
Es scheint sich aber um eine C-Stringliste zu handeln. Dort wird m.W. #0 als Trenner verwendet

ConnorMcLeod 28. Apr 2011 08:42

AW: Problem mit procedure Split()
 
Zitat:

Zitat von FredlFesl (Beitrag 1097309)
Deine Funktion kommt nur mit kurzen Strings klar und ist vom Aufwand O(n^2), weil für jedes Token immer von Anfang an gesucht wird. Ob das Schneller ist, bezweifle ich mal ganz stark.

War auch nur mal als Anfangs-Denkanstoss gedacht. Ich habe auch schon meine eigene Version daraus gemacht, die z.B. nicht immer beim Beginn beginnt, und die macht den Job sehr gut.

Zitat:

Zitat von FredlFesl (Beitrag 1097309)
Im Gegensatz dazu ist die TStringList-Geschichte sehr viel mächtiger, denn sie kommt mit allen Stringtypen und mit in Gänsefüschen eingeschlossenen Texten klar, z.B. wird
Delphi-Quellcode:
a,"b,c",d
in drei Strings ("a", "b,c" und "d") aufgeteilt.

Wenn man das will bzw braucht ... klar. Kann man aber auch in die Parserfunktion hineinprogrammieren, oder?
Zitat:

Zitat von FredlFesl (Beitrag 1097309)
Der Code von TStringlist sieht auch ganz schön flott aus.

Stimmt, aber es hängt eben ein komplettes Objekt hinten dran und das ist für meinen Geschmack *zu* mächtig (mächtig viel Verwaltungsaufwand nämlich). Was das erste Codebeispiel auch verschweigt: einen try-finally-Block brauchen wir korrekterweise noch zusätzlich.

Aber es ist im Endeffekt alles Geschmacksache und der beste Code ist der, der den Job erledigt und vom Kunden bezahlt wird ;-)

himitsu 28. Apr 2011 09:25

AW: Problem mit procedure Split()
 
Nur leider ist die TStringList, bzw. alle Strings-Nachfahren, beim Input, nur auf einen einzelnen String ausgelegt und keine C-Stringliste.

Delphi-Quellcode:
procedure CStringArrayToStringList(const StringArray: String; SL: TStrings);
var
  P: PChar;
begin
  SL.BeginUpdate;
  try
    SL.Clear;
    P := PChar(StringArray);
    if (P^ <> #0) or ((P + 1)^ <> #0) then
      repeat
        SL.Add(P);
        Inc(P, StrLen(P) + 1);
      until P = #0;
  finally
    SL.EndUpdate;
  end;
end;

[unnützes Wissen]
die ResourceStrings werden auch so verwaltet ... jeweils 16 in einem solchen StringArray

blackfin 28. Apr 2011 12:29

AW: Problem mit procedure Split()
 
Hast du mal versucht, deiner Liste die Eigenschaft "StrictDelimiter" auf true zu setzen, bevor zu splittest:

Delphi-Quellcode:
procedure Split(const Delimiter: Char; Input: string; const Strings: TStrings);
begin
   Strings.Clear;  
   Strings.Delimiter := Delimiter;
   Strings.StrictDelimiter:= True; // <--- hier
   Strings.DelimitedText := Input;
end;

Zitat:

TStrings.StrictDelimiter Eigenschaft

Legt fest, wie die Eigenschaft Delimiter verwendet wird.
Klasse
TStrings

Syntax


[Delphi] property StrictDelimiter: Boolean read GetStrictDelimiter write SetStrictDelimiter;


Beschreibung
Mit dieser Eigenschaft legen Sie fest, ob Delimiter der einzige in der Eigenschaft DelimitedText verwendete Wert ist. Bei True werden die einzelnen Strings in DelimitedText nur durch das in Delimiter angegebene Zeichen getrennt. Bei False können die einzelnen Strings in DelimitedText durch ein Leerzeichen, ein nicht druckbares Zeichen oder dem in Delimiter angegebenen Zeichen getrennt werden.

DeddyH 28. Apr 2011 12:32

AW: Problem mit procedure Split()
 
In Delphi 5 gab es noch keinen StrictDelimiter.

uragan 28. Apr 2011 16:20

AW: Problem mit procedure Split()
 
Zitat:

Zitat von himitsu (Beitrag 1097353)
Nur leider ist die TStringList, bzw. alle Strings-Nachfahren, beim Input, nur auf einen einzelnen String ausgelegt und keine C-Stringliste.

Delphi-Quellcode:
procedure CStringArrayToStringList(const StringArray: String; SL: TStrings);
var
  P: PChar;
begin
  SL.BeginUpdate;
  try
    SL.Clear;
    P := PChar(StringArray);
    if (P^ <> #0) or ((P + 1)^ <> #0) then
      repeat
        SL.Add(P);
        Inc(P, StrLen(P) + 1);
      until P = #0;
  finally
    SL.EndUpdate;
  end;
end;

[unnützes Wissen]
die ResourceStrings werden auch so verwaltet ... jeweils 16 in einem solchen StringArray



komisch, bekomme ERROR: Unknown type: 'PChar'
Also wie ich sehe geht es nicht auf diese weise.
Hab versucht mit Pos() gibt auch 0 aus :(


Ist es möglich alle #0 im string zu löschen? oder auf was anderes zu verändern?

mkinzler 28. Apr 2011 16:25

AW: Problem mit procedure Split()
 
PChar ist eigentlich in der System-Unit deklarier, welche automatisch eingebunden wird :gruebel:
Du könntest versuchen die #0 durch einen anderen trenner zu ersetzen (StringReplace())

FredlFesl 28. Apr 2011 17:53

AW: Problem mit procedure Split()
 
Also wenn ich einen PChar habe, und der zeigt auf Strings, die mit #0 voneinander getrennt sind, und zusätzlich habe ich noch die Gesamtlänge des Speicherbereiches, dann liegt es doch nahe, einfach mal durchzulaufen und ein ARRAY OF PCHAR oder eine TList zu erstellen, wenn man auf ein #0 stößt

Delphi-Quellcode:
Function SplitByNullChar (P : PChar; N : Integer) : TList;
Var
  I : Integer;
  C : Char;
Begin
  Result := TList.Create;
  Result.Add(P);
  For I :=1 to N-1 Do begin
    C := P^;
    Inc(P);
    If C=#0 then Result.Add(P);
  End;
End;
Voraussetzung: Hinter dem letzten String ist ein #0.

Danach stehen in der TList lauter PChars, die jeweils auf das erste Zeichen des Tokens zeigen. Terminiert wird dieser String ja durch ein #0, nämlich den nächsten Delimiter.

ConnorMcLeod 28. Apr 2011 18:20

AW: Problem mit procedure Split()
 
Klingt elegant (ausser dass man höllisch aufpassen muss, wer die TList wieder freigibt). Aber soweit ich das verstanden habe MUSS es eine TStringList sein (Aufgabenstellung?). So gesehen läge es auch nahe, eine eigene Ableitung zu machen und im Setter
Delphi-Quellcode:
TMyStrings.SetDelimitedText
die #0 extra freundlich zu behandeln.

uragan 29. Apr 2011 22:29

AW: Problem mit procedure Split()
 
Function SplitByNullChar (P : PChar; N : Integer) : TList;

PChar gibt es nicht :(

EWeiss 29. Apr 2011 22:41

AW: Problem mit procedure Split()
 
Zitat:

Zitat von uragan (Beitrag 1097741)
Function SplitByNullChar (P : PChar; N : Integer) : TList;

PChar gibt es nicht :(

warum PChar und nicht pointer of char

gruss

himitsu 29. Apr 2011 23:40

AW: Problem mit procedure Split()
 
Weil PChar schon ein Pointer auf einen oder mehrere Chars ist?

Wenn es PChar nicht gibt, dann stimmt irgendwas nicht
und man sollte erstmal dieses Problem beheben.

EWeiss 30. Apr 2011 00:01

AW: Problem mit procedure Split()
 
Zitat:

Zitat von himitsu (Beitrag 1097748)
Weil PChar schon ein Pointer auf einen oder mehrere Chars ist?

Wenn es PChar nicht gibt, dann stimmt irgendwas nicht
und man sollte erstmal dieses Problem beheben.

LOL ;)

Ist mir schon klar..
Aber anscheinend hat er kein PChar oder steht ihm nicht zur verfügung.
Zitat:

PChar gibt es nicht
Also muss er den Pointer selbst erstellen als Pointer of Char.

gruss

himitsu 30. Apr 2011 00:10

AW: Problem mit procedure Split()
 
Zitat:

Zitat von EWeiss (Beitrag 1097755)
Zitat:

PChar gibt es nicht
Also muss er den Pointer selbst erstellen als Pointer of Char.

Oder er sagt uns mal warum es PChar nicht gibt, bzw. ob dieses einfach nur nicht verwendet werden darf.

uragan 30. Apr 2011 01:44

AW: Problem mit procedure Split()
 
Liste der Anhänge anzeigen (Anzahl: 1)
wie siehts aus wenn man das ganze so macht?
weiß jemand wieso das ganze nicht klappt?

Delphi-Quellcode:
var

list2: TStringList;
res : string;
i : integer;

procedure Split(const Delimiter: Char; Input: string; Strings: TStrings);
var
   setstring : string;
   StringsTemp : TStringList;
begin
   StringsTemp := TStringList.create;
   Strings.Clear;
   while setstring <> '' do begin
   StringsTemp.Clear;
   StringsTemp.Delimiter := Delimiter;
   StringsTemp.DelimitedText := Input;
   Strings.Add(StringsTemp[0]);
   setstring := StringsTemp[0];
   Delete(Input,0,Length(StringsTemp[0])+1);
   end;
end;

begin
list2 := TStringList.create;
res := 'test1'+#0+'test1'+#0+'test1'+#0 ;
Split(#0, res, list2);
for i := 0 to list2.count-1 do begin
   ShowMessage(list2[i]);
end;
end.

EDIT::

Hab das ganze versucht in eine datei abzuspeichern


Code:
62 6c 61 62 6c 61 00 0d 0a
62 6c 61 62 6c 61 32 00 0d 0a
62 6c 61 62 6c 61 33 00 0d 0a
Es wird in der Datei angezeigt
Code:
blabla
blabla2
blabla3

Wenn ich per TStringList.LoadFromFile die selbe datei lade, dann wird nur der erste eintrag abgerufen, und danach ist stop.
D.h. nach wiederholtem abspeichern auf die selbe datei ist es nur noch:

Code:
62 6c 61 62 6c 61 00
Code:
blabla
echt komisch :(

PS: Datei liegt im Anhang, falls jemand probieren möchte

DeddyH 30. Apr 2011 07:24

AW: Problem mit procedure Split()
 
Das liegt an der 0, das ist in Delphi nun einmal das Stringende-Zeichen, wurde aber bereits mehrfach gesagt.

mkinzler 30. Apr 2011 08:31

AW: Problem mit procedure Split()
 
Zitat:

Das liegt an der 0,
Eigentlich dass von C

uragan 30. Apr 2011 10:52

AW: Problem mit procedure Split()
 
Ist es nicht möglich die Funktion Trim() so umzubauen, dass es alle #0 löscht?

himitsu 30. Apr 2011 11:08

AW: Problem mit procedure Split()
 
Trim entfernt doch jetzt schon alle führenden und nachfolgenden #0-en ? :gruebel:

uragan 30. Apr 2011 11:50

AW: Problem mit procedure Split()
 
Entfernt doch Leerzeichen oder? also #20

himitsu 30. Apr 2011 12:00

AW: Problem mit procedure Split()
 
Alle Steuerzeichen, von #0 bis #$20 (aka #32).

uragan 30. Apr 2011 12:04

AW: Problem mit procedure Split()
 
komischt, wenn ich ein string erzeuge zb.
Code:
'blabla' + #0
dann wird #0 nicht mit Trim entfernt

himitsu 30. Apr 2011 12:07

AW: Problem mit procedure Split()
 
Bei meinem Delphi schon.
Welche Delphi-Version hast du denn?

uragan 30. Apr 2011 12:19

AW: Problem mit procedure Split()
 
das weiß ich selber nicht genau welche delphi version das sein soll
ähnelt der version 5

EWeiss 30. Apr 2011 15:26

AW: Problem mit procedure Split()
 
Zitat:

Zitat von uragan (Beitrag 1097850)
das weiß ich selber nicht genau welche delphi version das sein soll
ähnelt der version 5

O o..

gruss

uragan 30. Apr 2011 19:34

AW: Problem mit procedure Split()
 
das ist nicht direkt delphi, das ist ein anderes Programm, benutzt aber die Delphi Sprache

himitsu 1. Mai 2011 00:12

AW: Problem mit procedure Split()
 
FreePascal (FPC) oder Lazarus?

Nja, in dem Fall hast du ja sowieso die Quellcodes zur Hand und könntest dir einfach mal ansehn wie Trim bei dir implementiert ist.

Bei mir wird auf
Delphi-Quellcode:
<= ' '
verglichen und demnach alle unteren Steuerzeichen #0 bis #31 und das Leerzeichen (#32) entfernt.

uragan 1. Mai 2011 00:50

AW: Problem mit procedure Split()
 
hmm, mache hier 200 zeilen code, und zum schluss:

Delphi-Quellcode:
while pos(#0,s)>0 do begin
delete(s,pos(#0,s),1);
end;
danach klappt auch die Split Funktion

ärgerlich, aber klappt super :)

FredlFesl 1. Mai 2011 07:44

AW: Problem mit procedure Split()
 
Performance ist Dir egal, oder? Dein Code ist nämlich sehr langsam, da würde der Algorithmiker Pickel bekommen... ;-)

mkinzler 1. Mai 2011 11:39

AW: Problem mit procedure Split()
 
Man könte auch mit StringReplace() versuchen

uragan 1. Mai 2011 12:28

AW: Problem mit procedure Split()
 
hatte auch mit StringReplace() versucht, doch leider gibt es diese Funktion nicht :(


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:01 Uhr.
Seite 1 von 2  1 2      

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-2025 by Thomas Breitkreuz