| Autor |
Beitrag |
Jiss
Hält's aus hier
Beiträge: 8
|
Verfasst: Fr 06.11.09 01:04
Hi,
ich lese aus einer Text-Datei mehrere Zeilen aus, die wie folgt aufgebaut sind:
Quelltext 1: 2: 3:
| BEZ :STUNDE (E/Ex/A/Ax/M/Mx/SM/SMx/T/Z/TN/B2/B8/B16/ANZ) (I/O) EW I BEZ :MINUTE (E/Ex/A/Ax/M/Mx/SM/SMx/T/Z/TN/B2/B8/B16/ANZ) (I/O) MW I BEZ :ZEIT-H (E/Ex/A/Ax/M/Mx/SM/SMx/T/Z/TN/B2/B8/B16/ANZ) (I/O) MW O |
Die Zeilen sind also immer nach Schema F aufgebaut.
Da ich aber nicht nur solche Zeilen auslesen möchte suche ich nach einer Funktion, die unter C als Scanf bekannt ist.
Damit ist es ja möglich einen formatierten String zu zerlegen und einzelne Teile des String zu speichern.
Beispiel:
scanf('%d hallo %f', var_zahl, var_float);
Für ne Zeile: "12345 hallo 123,45". In den Variablen werden also die Zahlen gespeichert.
Die Format-Funktion macht das ja genau andersrum. Nämlich die Werte von Variablen in einen String einfügen und diesen ausgeben. Gibts da auch ne Funktion, die genau andersrum funktioniert?
Es handelt sich bei mir nur um die Verarbeitung von String und keinen Zahlen.
Sicher kann ich einfach ab der so und so vielten Stelle die Werte mit Copy rauskopieren, aber so ne Scanf-Funktion wäre da einiges eleganter, um das Programm übersichtlich zu gestalten.
Gruß
Jörg
|
|
Xentar
      
Beiträge: 2077
Erhaltene Danke: 2
Win XP
Delphi 5 Ent., Delphi 2007 Prof
|
Verfasst: Fr 06.11.09 10:23
Für Delphi ist mir solch eine Funktion nicht bekannt.
Aber such mal nach regular expressions (RegEx), vielleicht helfen die dir weiter?
_________________ PROGRAMMER: A device for converting coffee into software.
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 06.11.09 10:54
Hallo und  !
Direkt gibt es das nicht. Wenn die Trennzeichen aber immer die Leerzeichen sind, dann kannst du auch mit TStringList arbeiten, genauer gesagt mit Delimiter und DelimitedText zum Beispiel.
Eine Alternative wären zwar die bereits genannten reguläre Ausdrücke. Das gibt es auch für Delphi. Das wäre aber in diesem Fall mit Boden-Luft-Raketen auf Spatzen geschossen.
// EDIT 2:
Am besten geht es wohl wie auch die diversen Splitfunktionen so: 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 SplitEx(const AText: string; ADelim: Char; ATarget: TStringList); overload; var CurTarget, CurChar: PChar; begin CurChar := PChar(AText); CurTarget := CurChar; while (CurChar^ <> #0) or (CurTarget <> nil) do begin if (CurChar^ = ADelim) or (CurChar^ = #0) then begin if CurTarget <> nil then begin ATarget.Add(Copy(CurTarget, 1, Integer(CurChar) - Integer(CurTarget))); CurTarget := nil; end; end else if CurTarget = nil then CurTarget := PChar(CurChar); Inc(CurChar); end; end;
procedure TForm235.Button1Click(Sender: TObject); var ExampleString: string; ExampleList: TStringList; begin ExampleString := 'BEZ :STUNDE (E/Ex/A/Ax/M/Mx/SM/SMx/T/Z/TN/B2/B8/B16/ANZ) (I/O) EW I'; ExampleList := TStringList.Create; try SplitEx(ExampleString, ' ', ExampleList); ShowMessage(ExampleList.Text); finally ExampleList.Free; end; end; |
Andere Alternativen: (EDIT: direktes Beispiel siehe unten) 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:
| procedure ScanF(const AText, ADelim: string; ATarget: array of PChar); var CurTargetIndex, CurTargetLength: Integer; CurTarget, CurChar, CurDelim: PChar; begin CurTargetIndex := 0; CurChar := PChar(AText); CurDelim := PChar(ADelim); CurTarget := CurChar; while (CurChar^ <> #0) or (CurTarget <> nil) do begin if (CurChar^ = CurDelim^) or (CurChar^ = #0) then begin if CurTarget <> nil then begin CurTargetLength := Integer(CurChar) - Integer(CurTarget); CopyMemory(ATarget[CurTargetIndex], CurTarget, Succ(CurTargetLength)); ATarget[CurTargetIndex][CurTargetLength] := #0; Inc(CurTargetIndex); CurTarget := nil; end; Inc(CurDelim); end else if CurTarget = nil then begin CurDelim := PChar(ADelim); CurTarget := PChar(CurChar); end; Inc(CurChar); end; end;
procedure TForm235.Button1Click(Sender: TObject); var a, b: string; begin SetLength(a, 255); SetLength(b, 255); ScanF('abc01abf', '01', [PChar(a), PChar(b)]); SetLength(a, StrLen(PChar(a))); SetLength(b, StrLen(PChar(b))); ShowMessage(a + #13#10 + b); end; | Für eine allgemeine Funktion sollte man noch prüfen, ob ATarget überhaupt lang genug ist usw., aber das sollte in diesem Fall ja nicht notwendig sein.
In deinem Fall musst du noch die unterschiedliche Anzahl von Leerzeichen beachten. Aber das lässt sich ja einbauen. Zum Beispiel, dass eine beliebige Anzahl Trennzeichen erkannt wird oder sowas.
// EDIT:
Funktionierendes Beispiel für das aktuelle Beispiel: 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: 47: 48: 49:
| procedure ScanF(const AText: string; ADelim: Char; ATarget: array of PChar); var CurTargetIndex, CurTargetLength: Integer; CurTarget, CurChar: PChar; begin CurTargetIndex := 0; CurChar := PChar(AText); CurTarget := CurChar; while (CurChar^ <> #0) or (CurTarget <> nil) do begin if (CurChar^ = ADelim) or (CurChar^ = #0) then begin if CurTarget <> nil then begin if CurTargetIndex >= Length(ATarget) then raise Exception.Create('Not enough space in array for ScanF(''' + AText + ''')'); CurTargetLength := Integer(CurChar) - Integer(CurTarget); CopyMemory(ATarget[CurTargetIndex], CurTarget, Succ(CurTargetLength)); ATarget[CurTargetIndex][CurTargetLength] := #0; Inc(CurTargetIndex); CurTarget := nil; end; end else if CurTarget = nil then CurTarget := PChar(CurChar); Inc(CurChar); end; end;
procedure TForm235.Button1Click(Sender: TObject); var ExampleString, a, b, c, d, e, f: string; begin ExampleString := 'BEZ :STUNDE (E/Ex/A/Ax/M/Mx/SM/SMx/T/Z/TN/B2/B8/B16/ANZ) (I/O) EW I'; SetLength(a, Length(ExampleString)); SetLength(b, Length(ExampleString)); SetLength(c, Length(ExampleString)); SetLength(d, Length(ExampleString)); SetLength(e, Length(ExampleString)); SetLength(f, Length(ExampleString)); ScanF(ExampleString, ' ', [PChar(a), PChar(b), PChar(c), PChar(d), PChar(e), PChar(f)]); SetLength(a, StrLen(PChar(a))); SetLength(b, StrLen(PChar(b))); SetLength(c, StrLen(PChar(c))); SetLength(d, StrLen(PChar(d))); SetLength(e, StrLen(PChar(e))); SetLength(f, StrLen(PChar(f))); ShowMessage(a + #13#10 + b + #13#10 + c + #13#10 + d + #13#10 + e + #13#10 + f); end; | Die Umwandlung in Zahlen oder so muss zwar im Gegensatz zum Original-ScanF noch erfolgen, aber das wird in Delphi kaum sinnvoll anders gehen. Auch wenn es theoretisch mit varianten Arrays möglich wäre.
Zuletzt bearbeitet von jaenicke am Sa 07.11.09 07:38, insgesamt 1-mal bearbeitet
|
|
Jiss 
Hält's aus hier
Beiträge: 8
|
Verfasst: Fr 06.11.09 23:38
Vielen Dank jaenicke. Das werde ich gleich nächste Woche ausprobieren.
|
|
|