![]() |
Herauslösen eines Strings im string
Hallo liebe DP !
Ich hab einige "Datensätze" in einer Textdatei abgelegt in diesem Format:
Code:
sieht dann so aus:
ID,[HEADLINE],TEXT1=TEXT2
Code:
Diese Datensätze werden zeilenweise in eine Listbox eingelesen. Wenn ich nun einen Eintrag selektiere, möchte ich einen Datensatz in seine Bestandteile zerlegen. Das hab ich so erledigt:
12345,[WASSER],Wasser ist, wie es ist=Muss geschützt werden, oder?
Delphi-Quellcode:
Das funktioniert mit der ID problemlos, allerdings kann ich den Text zwischen den [ ] nicht richtig herauslösen, ich bekomme immer noch 3 Zeichen zusätzlich angezeigt. Aus
procedure TForm1.ListBox2Click(Sender: TObject);
var s_1,s_2,s_3, s_4:string; ipos, yPos, x1pos, x2Pos:integer; begin //Allen 4 Strings den selbe Zeile zuweisen s_1 := ListBox2.Items[ListBox2.ItemIndex]; s_2 := ListBox2.Items[ListBox2.ItemIndex]; s_3 := ListBox2.Items[ListBox2.ItemIndex]; s_4 := ListBox2.Items[ListBox2.ItemIndex]; //String1 = ID herauslösen yPos := Pos (',', s_1);//erstes Komma finden if (yPos > 0) then begin //Komma gefunden Delete(s_1,ypos, s_1.Length-1); Delete(s_2,1, yPos); e_id.Text:=s_1; end; //String HEADLINE herauslösen x1Pos := Pos ('[', s_4); if (x1Pos > 0) then begin //erste Klammer gefunden, jetzt 2. Klammer suchen x2Pos := Pos (']', s_4); if (x2Pos > 0) then begin //jetzt zurechtschneiden Delete(s_4,1, x1Pos); Delete(s_4,x2Pos,s_4.Length-1); showmessage(s_4); end; end; //STRING TEXT1 .... End;
Code:
soll
ID,[HEADLINE],TEXT1=TEXT2
Code:
werden, ist aber
HEADLINE
Code:
Komischerweise ist
HEADLINE],TE
Delphi-Quellcode:
völlig korrekt und schneidet alles bis zur ersten [ ab.
Delete(s_4,1, x1Pos);
AUch
Delphi-Quellcode:
schneidet alles ab ].
Delete(s_4,x2Pos,s_4.Length-1);
Beides zusammen:
Delphi-Quellcode:
bringt ein falsches Ergebnis.. :?:
Delete(s_4,1, x1Pos);
Delete(s_4,x2Pos,s_4.Length-1); showmessage(s_4); |
AW: Herauslösen eines Strings im string
Durch das erste Delete ändert sich die Stringlänge, deshalb passt der 2. Index nicht mehr. Benutz doch statt 2 * Delete 1 * Copy, dann hast Du das Problem nicht.
[edit] Alternativ kannst Du auch beim Delete bleiben, darfst dann aber x2Pos erst nach dem ersten Löschen ermitteln. [/edit] |
AW: Herauslösen eines Strings im string
oder wie man es bei Löschungen meist machen sollte, von hinten nach vorne
Delphi-Quellcode:
Gruß
Delete(s_4,x2Pos,s_4.Length-1);
Delete(s_4,1, x1Pos); showmessage(s_4); K-H |
AW: Herauslösen eines Strings im string
Anstatt immer nur mit
Delphi-Quellcode:
und
Pos()
Delphi-Quellcode:
zu arbeiten würde ich besser eine Funktion einsetzen die spezieller auf die Aufgabe zugeschnitten ist:
Delete()
Delphi-Quellcode:
Und dann:
function StrToken(var S: string; Separator: Char): string; // kopiert aus der JCL
var I: Integer; begin I := Pos(Separator, S); if I <> 0 then begin Result := Copy(S, 1, I - 1); Delete(S, 1, I); end else begin Result := S; S := ''; end; end;
Delphi-Quellcode:
Dieser Code ist wesentlich besser zu verstehen als die ganze Serie von Delete, Pos und Length.
s := ListBox2.Items[ListBox2.ItemIndex];
s_1 := StrToken(s, ','); // ID abtrennen s_2 := StrToken(s, ','); // Headline abtrennen Sollte in Zukunft ein ähnliches Problem anstehen, dann hast du gleich eine Funktion um es zu lösen. |
AW: Herauslösen eines Strings im string
Warum zerlegst du es erst wenn das angeklickt wird, wieso hängst du nicht gleich einen Datensatz an das Item und liest dann bequem die Infos aus dem Datensatz?
Delphi-Quellcode:
Evtl. mußt du vorher noch OwnsObjects auf True setzten. Bei Delphi 7 geht das nicht, bei deiner Version sollten die Eigenschaft vorhanden sein. Wenn OwnsObjects auf True ist, mußt du die Objekte beim Löschen der Items nicht vorher freigeben.
Type
TDatensatz = class ID: String; //oder Integer HEADLINE: String; TEXT1: String; TEXT2: String; end; procedure TForm1.Button1Click(Sender: TObject); var s: String; Datensatz: TDatensatz; begin s := '12345,[WASSER],Wasser ist, wie es ist=Muss geschützt werden, oder?'; Datensatz := TDatensatz.Create; Datensatz.ID := '12345'; Datensatz.HEADLINE := 'WASSER'; Datensatz.TEXT1 := 'Wasser ist, wie es ist'; Datensatz.TEXT2 := 'Muss geschützt werden, oder?'; with ListBox2 do Items.AddObject(s, Datensatz); end; procedure TForm1.ListBox2Click(Sender: TObject); var s: String; Datensatz: TDatensatz; begin with ListBox2 do if ItemIndex < 0 then Exit; with ListBox2 do s := Items[ItemIndex]; with ListBox2 do Datensatz := TDatensatz(Items.Objects[ItemIndex]); ShowMessage( 'Item-String: ' + s + #13#10 + 'ID: ' + Datensatz.ID + #13#10 + 'HEADLINE: ' + Datensatz.HEADLINE + #13#10 + 'TEXT1: ' + Datensatz.TEXT1 + #13#10 + 'TEXT2: ' + Datensatz.TEXT2 ); end; |
AW: Herauslösen eines Strings im string
Wenn die "Datensätze" aus einer Textdatei kommen, müssen sie doch trotzdem geparst werden. Von daher erschließt sich mir der Nutzen nicht so richtig.
|
AW: Herauslösen eines Strings im string
Hallo ihr lieben,
Ich habe etwas weiter experimentiert und dabei eure Vorschläge berücksichtigt. Zunächst hat DeddyH den Fehler in meines codes erkannt, der 2. index wird um die Zeichen verschoben, welche ich vorher entferne :thumb: Die Funktionslösung von sx2008 hat mir auch sehr gut gefallen, das ist in der Tat besser als meine Delete-Serie. Allerdings bekomm ich dann ein Problem, wenn der Datensatz keine [HEADLINE] hat. Dann stürzt sich die Funktion auf das nächste Komma, nämlich auf den Satzzeichen und zerpflückt den Text:
Code:
in
Wasser ist, wie es ist
Code:
Es kommt dann zum selben Problem wie in meiner Lösung: der Index passt nicht mehr.
wie es ist
Den Ansatz von Popov muss ich noch testen. Da die Listbox von einer Datei mit 400 Zeilen gespeist wird, müsste ich zunächst Zeile für Zeile:
Code:
als
'12345,[WASSER],Wasser ist, wie es ist=Muss geschützt werden, oder?'
Delphi-Quellcode:
einlesen.
Datensatz: TDatensatz;
|
AW: Herauslösen eines Strings im string
@DeddyH
Wird nicht allgemein behauptet, dass man Daten und Darstellung trennen sollte? @Ajintaro Würdest du die Daten in der Form speichern:
Code:
könntest du die Zeile in ein TStrings, bzw. TStringList als CommaText einlesen. Das Ergebnis wäre z. B. eine TStrigList mit vier Zeilen, von denen jede eine Info enthalten würde. In dem Fall würde das System für dich die Zeile trennen.
"ID","[HEADLINE]","TEXT1","TEXT2"
|
AW: Herauslösen eines Strings im string
Zitat:
|
AW: Herauslösen eines Strings im string
Wo steht das, dass Properties sein müssen?
Sicher, man kann das schöner und besser machen, aber für diese Aufgabe reicht es. |
AW: Herauslösen eines Strings im string
Zitat:
Nee, im Ernst: Passt scho' bei reinen DTO. Ich halte das auch -speziell bei Delphi- für Overkill, eine Klasse mit quasi Autoproperties anzulegen (die es in Delphi ja leider nicht gibt) und alles wozu diese Properties da sind, ist dann, ein privates Feld zu füllen oder zu liefern. Blödsinn. In C# ist das kein Problem, weil man einfach nur
Code:
schreibt. In Delphi muss man mal wieder nen halben Roman schreiben.
class Foo
string Bar{get;set;} .. |
AW: Herauslösen eines Strings im string
Und worin genau liegt der Zugewinn einer reinen Datenklasse zu einem statischen Array oder einem Record, außer dass man eine Klasse hat und damit "OOP programmiert"?
|
AW: Herauslösen eines Strings im string
Mit Hilfe eines OleVariant oder unter Ausnutzung der Funktionalitäten für TReader/TWriter (oder hast du im TTimer schonmal die Property Top und Left gefunden? ),
kann man auch sowas wie "virtuelle" Property schon seit Jahrzehnten in Delphi benutzen. Aber ich würde davon eher abraten, da, angefangen bei der Codevervollständigung und Codedokumentation, sowas nicht vorhanden und somit in der IDE und im Compiler (Fehlerprüfung) nicht nutzbar ist. Und wenn du keinen Getter/Setter scheiben willst, dann lass' ihn dir automatisch erstellen (für irgendwas muß duie Klassenvervollständigung ja gut sein) Bei
Delphi-Quellcode:
frag ich mich eher "Wo landet der Wert?".
string Bar{get;set;}
Delphi-Quellcode:
und am Ende ein Strg+Shift+C oder ein
property Bar: string;
Delphi-Quellcode:
geht doch auch. :angel:
propf[space]Bar[enter]string[enter]
|
AW: Herauslösen eines Strings im string
Zitat:
Delphi-Quellcode:
(die eckige Klammer ist ja der Seperator(?))
s := ListBox2.Items[ListBox2.ItemIndex];
s_1 := StrToken(s, '['); // ID abtrennen s_2 := StrToken(s, ']'); // Headline abtrennen Das sollte funktionieren. Wenn "[HEADLINE]" nicht enthalten ist, dann
Delphi-Quellcode:
und du kannst mit einem anderen Seperator weiter machen.
s=ListBox2.Items[ListBox2.ItemIndex];
Gruß K-H |
AW: Herauslösen eines Strings im string
Bin mir jetzt zwar nicht ganz sicher obs passt, liest sich aber so^^
Ein Bekannter hat mir vor einiger Zeit mal eine kleine Funktion geschrieben, die genau das tut was sie tut.
Delphi-Quellcode:
GIbt mir persönlich immer genau das zurück, was ich gerade suche
function getTextBetweenStrings(const source, startStr, endStr: String;
var offset: integer; includeSubstrings: Boolean = False): String; var startIndex, endIndex: integer; begin startIndex := PosEx(startStr, source, offset); offset := startIndex + 1; if (startIndex > 0) then begin startIndex := startIndex + Length(startStr); endIndex := PosEx(endStr, source, startIndex) + Length(endStr); if not includeSubstrings then endIndex := endIndex - Length(endStr) else startIndex := startIndex - Length(startStr); Result := MidStr(source, startIndex, endIndex - startIndex); end else Result := ''; end; Grüße Day |
AW: Herauslösen eines Strings im string
Hey schönen Montag euch allen,
Ich habe nun eine Lösung entwickelt, welche einen Mix aus euren Codevorschlägen darstellt. Mit unten stehendem Code kann ich
Code:
oder
99,10,Text1=Text2
Code:
komplett zerlegen:
99,Text1=Text2
Delphi-Quellcode:
So funktioniert es einwandfrei, obwohl da ne Menge Optimierungspotential drinsteckt :oops:
procedure TForm1.b_schneidenClick(Sender: TObject);
var s,s1,s2,s3,s4:string; zahl: double; ipos, xpos:integer; begin s := ListBox2.Items[ListBox2.ItemIndex];//markierte Zeile als Start-String s1 := StrToken(s, ','); // ID abtrennen s2 := StrToken(s, ','); // Headline abtrennen //Prüfen ob Headline überhaupt existiert if TryStrToFloat(s2, zahl) then begin //Headline ist vorhanden ! s3 := StrToken(s, ','); s4 := StrToken(s3, '='); end else begin //KEINE Headline vorhanden s2 := '99';//fake ID setzen s := ListBox2.Items[ListBox2.ItemIndex];//s neu setzen, weil leer.. //Dazwischen abschneiden iPos := Pos (',', s); if (iPos > 0) then begin Delete(s,1,ipos); //nochma schneiden xPos := Pos ('=', s); if (xPos > 0) then begin Delete(s,xpos,s.Length-1); e_qu.Text:=s; end; end; s := ListBox2.Items[ListBox2.ItemIndex];//s neu setzen, weil leer.. s4 := StrToken(s, '='); end; End; Ich danke euch ! |
AW: Herauslösen eines Strings im string
Zitat:
Delphi-Quellcode:
Nachteil: ExtractStrings kann keine leeren Einträge erzeugen - aber wenn die Daten alle in der Art sind wie deine Beispieldaten sollte das ausreichend funktionieren...
procedure TForm1.Button1Click(Sender: TObject);
var sl: TStringlist; begin sl := TStringLIst.Create; ExtractStrings([','],[' '], PChar(Edit1.Text), sl); Memo1.Text := sl.Text; sl.Free; end; |
AW: Herauslösen eines Strings im string
Zitat:
Gegenfrage: Wieso soll ich leere Getter/Setter deklarieren und überflüssige private Variablen einführen? weil man damit "OOP programmiert"? |
AW: Herauslösen eines Strings im string
Da fehlen noch 12 Factories mit 42 Interfaces, um eine Darstellungsform in eine andere umzuwandeln. Aber macht doch, was Ihr wollt, heute ist ja eh Pappnasenfeiertag :stupid:
|
AW: Herauslösen eines Strings im string
Zitat:
Und damit man sich die Möglichkeit offen hällt, da ml einen Getter/Setter granzumache. Und sei es nur um später das mal besser debuggen zu können. Und, wie gesagt, für den Programmierer ist es ja kein großer Mehraufwand. |
AW: Herauslösen eines Strings im string
Wenn wir schon mal beim Diskutieren sind: Viele dieser Stringzerlegungsaufgaben würden vermutlich nicht in der DP landen, wenn die Nutzung von reguläre Ausdrücke in der Delphi-Community verbreiteter wäre :mrgreen:
|
AW: Herauslösen eines Strings im string
dann los... wie können reguläre Ausdrücke bei diesem Problem helfen? Ich dachte immer die wären was fürs Suchen....
|
AW: Herauslösen eines Strings im string
Nun noch vollständigkeits- und spaßeshalber, eine weitere OOP-Möglichkeit:
Delphi-Quellcode:
procedure TForm1.ButtonAddClick(Sender: TObject);
begin with ListBox1 do Items.Add('12345,[WASSER],Wasser ist, wie es ist=Muss geschützt werden, oder?') end; procedure TForm1.ListBox1Click(Sender: TObject); var s, s1, s2, s3, s4: String; sl: TStringList; begin with ListBox1 do if ItemIndex < 0 then Exit; with ListBox1 do s := Items[ItemIndex]; sl := TStringList.Create; try sl.Add(s); s4 := sl.Values[sl.Names[0]]; sl.Delimiter := ','; sl.DelimitedText := sl.Names[0]; //kann man auch CommaText nehmen if sl.Count > 0 then s1 := sl[0] else s1 := ''; if sl.Count > 1 then s2 := sl[1] else s2 := ''; //hier evtl. noch die eckigen Klammern löschen if sl.Count > 2 then s3 := sl[2] else s3 := ''; finally sl.Free; end; ShowMessage( 'Item-String: ' + s + #13#10 + 'ID: ' + s1 + #13#10 + 'HEADLINE: ' + s2 + #13#10 + 'TEXT1: ' + s3 + #13#10 + 'TEXT2: ' + s4 ); end; |
AW: Herauslösen eines Strings im string
Zitat:
Das Geheimnis sind Capturing-Groups, wie sie von vielen Implementierungen angeboten werden. Ausgehend von den Beispielen:
Code:
Komm ich zu diesem Ausdruck:
99,10,Text1=Text2
99,Text1=Text2
Code:
Die Capturing-Groups sind:
([0-9]+),(?:([^,]*),)?([^=]*)=(.*)
Code:
import java.util.regex.*;
class PatternTest { static public void main(String[] args) { if (args.length == 1) { Pattern pattern = Pattern.compile("([0-9]+),(?:([^,]*),)?([^=]*)=(.*)"); Matcher matcher = pattern.matcher(args[0]); if (matcher.matches()) { // group 0 is the whole match for (int i = 1; i <= matcher.groupCount(); i++) { System.out.println(matcher.group(i)); } } else { System.out.println("No match!"); } } else { System.out.println("Nothing to match!"); } } } Gut, ich gebe zu: Das hat jetzt etwas länger gedauert als es sollte. Ich musste nochmal die nötigen Klassen und die Regex-Syntax nachgooglen :stupid: |
AW: Herauslösen eines Strings im string
Danke!
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:26 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