Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Pos, Copy usw.
Arbengie - Sa 12.06.10 13:35
Titel: Pos, Copy usw.
Hi ich veruche grad nen Programm zu schreiben, bei dem man in ein Edit einen String mit mehreren Werten rein einfügt (z.B. "WertA WertB WertC"). Diese sind alle durch eine Leerzeichen getrennt. Und in drei anderen Edit Felder sollen diese Werte dann alleine angezeigt werden.
Da habe ich bisher mit Copy, Pos gearbeitet, nur das Problem ist, dass es ja mehrere Leerzeichen gibt und Pos nur das Erste immer anerkennt...
Wie komm ich da weiter bzw. gibts da auch en ganz andere elegantere Möglichkeit?
Dude566 - Sa 12.06.10 13:38
Du könntest dein Konzept überlegen und vielleicht was sinnvolleres verwenden.
Du könntest aber auch nachdem du den 1. Wert herauskopiert hast diesen aus dem String löschen und dann den Rest weiterverarbeiten, wie ein Parser das auch macht.
Narses - Sa 12.06.10 13:42
Moin!
Wenig Aufwand: schau dir mal
TSTRINGLIST.COMMATEXT an. :idea: ;)
cu
Narses
ALF - Sa 12.06.10 13:47
Dude566 hat folgendes geschrieben : |
| Du könntest dein Konzept überlegen und vielleicht was sinnvolleres verwenden. |
Dem schliesse ich mich an. Da Du hier von Werte schreibst, gehe ich davon aus das es Zahlenwerte sind.
Warum also so kompliziert machen wenn man gleich 3 Editfelder dafür nehmen kann :wink:
Zumal Du dies ja in 3 Editfelder übertragen tust.
Gruss Alf
Arbengie - Sa 12.06.10 13:52
Also man kopiert ne Zeile aus dem Internet und fügt die dort ein und das Programm soll das dann halt "zerteilen"
Das was man reinkopiert is konkret:
"24 Red County Timo87 0 % 17 L 1104 km/2054 km"
Ich brauche daraus für Editfeld einen Wert(für das Bsp.):
-24
-Red County
-Timo87
-0
-17
-1104
ALF - Sa 12.06.10 13:55
Das ist ja was anderes, als das was in Deinem Anfang steht!
Ansonsten siehe
Narses
Gruss Alf
Arbengie - Sa 12.06.10 14:03
Ja, aber da sind keine Kommata, wie man sie für TStingList.CommaText brauch
Dude566 - Sa 12.06.10 14:06
Schreibe den Text aus dem Edit in eine Variable vom Typ String und zerlege dann diesen nach deinen Wünschen mit Pos etc in weitere Variablen, die du dann in deinen Edits einfügen kannst.
ALF - Sa 12.06.10 14:17
Arbengie hat folgendes geschrieben : |
| Ja, aber da sind keine Kommata, wie man sie für TStingList.CommaText brauch |
Dann solltest Du Dir mal die Hilfe durchlesen :!:
TStingList.Delimiter := Char, kann also (',') (' ') ('#') (':') sein usw.
Gruss Alf
Narses - Sa 12.06.10 14:28
Moin!
Arbengie hat folgendes geschrieben : |
| Ja, aber da sind keine Kommata, wie man sie für TStingList.CommaText brauch |
Das ist auch nicht unbedingt wichtig, WhiteSpace zählt wie Komma. Einfach mal ausprobieren. :)
cu
Narses
Arbengie - Sa 12.06.10 14:58
Hab mal was versucht wie es in manchen Beispielen gemacht wird:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| Input.Text := '24 Red County Timo87 0 % 17 L 1104 km/2054 km';
procedure TForm1.Button1Click(Sender: TObject); var input: TStringList; s1: string; begin input := TStringList.Create; input.CommaText := edtinput.Text; s1 := input.Values['24']; Edtoutput.Text := s1; end; |
Fehler: Nix passiert :P
Delete - Sa 12.06.10 15:13
Und wo wird die Stringliste wieder freigegeben? Wo ist der Ressourcenschuttzblock? Wo ist die Fehlerbehandlung?
jaenicke - Sa 12.06.10 15:17
Values bringt dir hier wenig, da du keine Zeilen wie "24=Mein Wert" hast. Du brauchst input[0], input[1], ...
Wobei hier ein manuelles Vorgehen sinnvoller wäre. Denn automatisch bekommt man das doppelte Leerzeichen nicht als Trennzeichen hin.
jaenicke - Sa 12.06.10 17:08
Mal nen ganz schnell hingezimmerter Versuch, sollte klappen, hab grad kein Delphi zum Testen da (jetzt erst Recht mit Pointern :mrgreen:):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43:
| type TExampleData = record Age, Group, Name, Progress, L, Position: string; procedure LoadFromString(const Value: string); end;
procedure TExampleData.LoadFromString(const Value: string); var CurPos, CurValue, NextPos: PChar; CurData: PString; Count: Integer; begin CurPos := @Value[1]; CurValue := CurPos; CurData := @Age; while CurPos^ <> #0 do begin NextPos := PChar(Integer(CurPos) + SizeOf(Char)); if ((CurPos^ = ' ') and (NextPos^ = ' ')) or (NextPos^ = #0) then begin Count := Integer(CurPos) - Integer(CurValue); if NextPos^ = #0 then Inc(Count); CurData^ := Copy(CurValue, 1, Count); Inc(CurData); Inc(CurPos); CurValue := CurPos; Inc(CurValue); end; Inc(CurPos); end; end;
var ExampleRecord: TExampleData; begin ExampleRecord.LoadFromString(edtInput.Text); memResult.Lines.Add(ExampleRecord.Age); memResult.Lines.Add(ExampleRecord.Group); memResult.Lines.Add(ExampleRecord.Name); memResult.Lines.Add(ExampleRecord.Progress); memResult.Lines.Add(ExampleRecord.L); memResult.Lines.Add(ExampleRecord.Position); |
Sollte ab Delphi 2006 / Turbo Delphi so gehen.
delfiphan - Sa 12.06.10 18:49
jaenicke hat folgendes geschrieben : |
| (...) ganz schnell (...) hingezimmerter Versuch (...) hab grad kein Delphi zum Testen (...) Pointern |
:bawling:
Arbengie, hast du Einfluss auf das Eingabeformat? Ich würde dir raten, ein Standardformat wie CSV zu verwenden. Felder mit zwei Leerzeichen zu trennen, weil die Felder selbst Leerzeichen haben klingt für mich nicht nach einem robusten Design. Falls du keinen Einfluss hast; im Internet solltest du eine geeignete Stringsplitter oder Explode Routine finden. Du bist bestimmt nicht der erste ;)
jaenicke - So 13.06.10 08:41
So, ich habe es noch getestet, funktioniert natürlich auch. Hier noch eine zweite Variante:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46:
| type TExampleData = record Age: Integer; Group, Name: string; Progress, L, Position: Integer; procedure LoadFromString(const Value: string); procedure LoadFromString2(const Value: string); end;
procedure TExampleData.LoadFromString(const Value: string); var CurPos, CurValue, NextPos, BlankPos: PChar; CurData: Pointer; Count, Index: Integer; begin CurPos := @Value[1]; CurValue := CurPos; CurData := @Age; Index := 0; BlankPos := nil; while CurPos^ <> #0 do begin if (CurPos^ = ' ') and not Assigned(BlankPos) then BlankPos := CurPos; NextPos := PChar(Integer(CurPos) + SizeOf(Char)); if ((CurPos^ = ' ') and (NextPos^ = ' ')) or (NextPos^ = #0) then begin Count := Integer(CurPos) - Integer(CurValue); if NextPos^ = #0 then Inc(Count); case Index of 0: TryStrToInt(Copy(CurValue, 1, Count), PInteger(CurData)^); 1, 2: PString(CurData)^ := Copy(CurValue, 1, Count); 3..5: TryStrToInt(Copy(CurValue, 1, Integer(BlankPos) - Integer(CurValue)), PInteger(CurData)^); end; Inc(PLongWord(CurData)); Inc(CurPos); CurValue := CurPos; Inc(CurValue); Inc(Index); BlankPos := nil; end; Inc(CurPos); end; end; |
Und ohne Pointerspielerei die "normale" Version für den Recordzugriff:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36:
| procedure TExampleData.LoadFromString(const Value: string); var CurPos, CurValue, NextPos, BlankPos: PChar; Count, Index: Integer; begin CurPos := @Value[1]; CurValue := CurPos; Index := 0; BlankPos := nil; while CurPos^ <> #0 do begin if (CurPos^ = ' ') and not Assigned(BlankPos) then BlankPos := CurPos; NextPos := PChar(Integer(CurPos) + SizeOf(Char)); if ((CurPos^ = ' ') and (NextPos^ = ' ')) or (NextPos^ = #0) then begin Count := Integer(CurPos) - Integer(CurValue); if NextPos^ = #0 then Inc(Count); case Index of 0: TryStrToInt(Copy(CurValue, 1, Count), Age); 1: Group := Copy(CurValue, 1, Count); 2: Name := Copy(CurValue, 1, Count); 3: TryStrToInt(Copy(CurValue, 1, Integer(BlankPos) - Integer(CurValue)), Progress); 4: TryStrToInt(Copy(CurValue, 1, Integer(BlankPos) - Integer(CurValue)), L); 5: TryStrToInt(Copy(CurValue, 1, Integer(BlankPos) - Integer(CurValue)), Position); end; Inc(CurPos); CurValue := CurPos; Inc(CurValue); Inc(Index); BlankPos := nil; end; Inc(CurPos); end; end; |
Wichtig: Fehlerbehandlung fehlt in beiden noch, denn Umwandlungsfehler werden zwar abgefangen, aber nicht behandelt.
delfiphan hat folgendes geschrieben : |
jaenicke hat folgendes geschrieben : | | (...) ganz schnell (...) hingezimmerter Versuch (...) hab grad kein Delphi zum Testen (...) Pointern |
:bawling: |
Ich habe es mir schon gut genug überlegt was da passiert. ;-)
delfiphan - So 13.06.10 09:40
jaenicke hat folgendes geschrieben : |
| Wichtig: Fehlerbehandlung fehlt in beiden noch, denn Umwandlungsfehler werden zwar abgefangen, aber nicht behandelt. |
Der Code gefällt mir auch aus einigen anderen Gründen nicht.
Es fehlt die Validierung des Inputs; habe ich Range Checking eingeschaltet, geht's bei einem leeren String schief; ist Overflow Checking eingeschaltet, geht deine Integer Arithmetik bei Pointern vielleicht schief, wenn mit PEFlags $20 kompiliert. Ganz nebenbei sollte das Umwandeln von Pointer zu Integer tabu sein (wenn schon dann Cardinal oder UINT_PTR). Ungeachtet von Range Checking kann ich mit dem Code leicht Memory überschreiben, indem ich zu viele Werte übergebe. Dein Code ist stark platformabhängig und macht Annahmen über die interne Struktur von Strings. Kein Separation of Concern vorhanden, deine Funktion macht alles gleichzeitig und ist daher recht unübersichtlich und nicht wiederverwendbar (bei zwei ähnlichen Funktionen müsstest du das ganze mehr oder weniger 1:1 kopieren und modifizieren; wenn du einen Bug findest musst du es an zwei Orten fixen; wenn man "zwei Leerzeichen" durch "Tab" ersetzt, musst ggf. alles neu überlegen und umschreiben). Ich finde es übrigens besser, Fehler als solche zu schmeissen, statt stillschweigend mit TryStrToInt zu ignorieren.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!