Zugriff auf Textdatei mit TStringList

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
ErnstVolker
Beiträge: 353
Registriert: Di 17. Feb 2009, 10:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Zugriff auf Textdatei mit TStringList

Beitrag von ErnstVolker »

Hallo zusammen,

ich bin gerade dabei eine Textdatei mit TStringList zu "beackern". Die Datei (zum Testen abgespeckt) sieht so aus:

Code: Alles auswählen

DATRKAKT-START
 
	DATRKAFH-START
		KAFH_HST_BENN_K	"Mercedes-Benz"
	DATRKAFH-END
 
	DATRKTBA-START
		KTBA_NAME	"VIN_DATEN           "
	DATRKTBA-END
 
DATRKAKT-END
d.h. Es sind Einrückungen über Tabulator und Leerzeilen vorhanden.
Ziel ist, das "Mercedes-Benz" "heraus zu schneiden" und in eine extra Textadtei wegzuschreiben, aber nur dann, wenn bei KTBA_NAME auch VIN-Daten eingetragen ist.

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var offen: Boolean; Datei: TStringList; wo: Integer;
const Anf_1: String = 'DATRKAKT-START'; END_1: String = 'DATRKAKT-END';
      Anf_2: String = 'DATRKAFH-START'; END_2: String = 'DATRKAFH-END';
      Anf_3: String = 'DATRKTBA-START'; END_3: String = 'DATRKTBA-END';
      Herst: String = 'KAFH_HST_BENN_K'; VIN: String = 'KTBA_NAME';
begin
  offen := OpenDialog1.Execute;
  Datei := TStringList.Create;
  Datei.LoadFromFile(UTF8ToSys(OpenDialog1.FileName));
  Memo1.Lines := Datei;
  //Datei.Find(Anf_1,wo);
  //label1.Caption := IntToStr(wo);
  label1.Caption := IntToStr(Datei.IndexOf(Anf_1));
  Datei.Free;
end;
Jetzt stehe ich am Anfang und habe schon das Problem, dass "Find" oder auch "IndexOf" nicht mit den Einrückungen und Leerzeilen zurechtkommen.
Bearbeite ich die Datei von Hand und richte alles linksbündig aus, dann findet "IndexOf" die entsprechenden Zeilen, bis auf die Beiden wo "Mercedes-Benz" bzw "VIN-Daten" hinter steht.

Um die Einrückungen herauszubekommen dachte ich an Trim(Datei) bzw TrimLeft(Datei). Das funzt aber nicht, da kommt die Meldung dass die Trim-Befehle nur mit UnicodeString arbeiten. Ein TypCasting auf UnicodeString Trim(UnicodeString(Datei)) liefert während des Programmlaufes eine Zugriffsverletzung.

Hat von Euch jemand eine Idee?

Vielen Dank vorab.

Grüße

Volker

Benutzeravatar
theo
Beiträge: 10872
Registriert: Mo 11. Sep 2006, 19:01

Re: Zugriff auf Textdatei mit TStringList

Beitrag von theo »

Ich würde da wahrsch. zeilenweise vorgehen und erst einmal die Datei insgesamt in eine interne Struktur einlesen, kommt halt auf die Grösse an.
Die Struktur kapier ich so natürlich auch nicht.

ErnstVolker
Beiträge: 353
Registriert: Di 17. Feb 2009, 10:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Zugriff auf Textdatei mit TStringList

Beitrag von ErnstVolker »

Hallo theo,

was verstehst Du unter einer internen Struktur? Einen Zugriff über "AssignFile" und dann mit "repeat until EOF" zeilenweise durchgehen?

Für den Aufbau der Datei kann ich nix. Die wird mir so geliefert. Da Stehen Fahrzeuge drinnen, einschließlich Austattung usw. Jedes Fahrzeug fängt immer mit
DATRKAKT-START an und hört mit DATRKAKT-END auf. Dazwischen steht jede Menge Zeugs, u.a. auch die Zeilen mit KAFH_HST_BENN_K "Hersteller-Bezeichnung" bzw.
KTBA_NAME "VIN_DATEN ". Und dies wiederum ist immer eingeschlossen mit *****-Start und *****-End. Da stehen dann auch wieder reichlich Textzeilen dazwischen die für mein Problem nicht von Belang sind.

Problem ist die Grösse. Die Datei kann schon mal 5 MB oder auch mehr erreichen.

Am einfachsten wäre immer nur nach KAFH_HST_BENN_K "Hersteller-Bezeichnung" zu suchen und den Hersteller wegzuschreiben. Anschließend lese ich es in OOCalc ein und zähle über Pivot-Tabelle die Anzahl der Fahrzeuge eines Herstellers. Das ganze dient der Rechnungskontrolle.

Gruß

Volker

Benutzeravatar
theo
Beiträge: 10872
Registriert: Mo 11. Sep 2006, 19:01

Re: Zugriff auf Textdatei mit TStringList

Beitrag von theo »

Nee, ich würde einfach zeilenweise aus der StringList die Informationen auslesen bzw. in eine passende Struktur in den Speicher lesen.
Also in eine TList von TAuto mit den Benötigten Feldern oder so. Aber was das genau ist, musst du selber wissen.
Ich meine nur, mit IndexOf kommst du da wohl kaum weiter, das Ding muss man schon irgendwie parsen, denke ich.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6780
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Zugriff auf Textdatei mit TStringList

Beitrag von af0815 »

Die Struktur ist doch xml ähnlich.

Die Frage ist, entweder Tools für xml zu patchen oder die Datei ganz einfach nach xml umzuformen und dann mit xmltools zu bearbeiten.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

ErnstVolker
Beiträge: 353
Registriert: Di 17. Feb 2009, 10:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Zugriff auf Textdatei mit TStringList

Beitrag von ErnstVolker »

Hallo,

ich habe mich für die für mich am einfachsten durchzuführende Variante entschieden:

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var offen: Boolean; Datei, Ausgabe: TextFile; wo: Integer; Pfad, AusNamePfad, AusName, Zeile, Teil: AnsiString;
    option: TReplaceFlags;
const 
      Herst: String = 'KAFH_HST_BENN_K'; 
begin
  offen := OpenDialog1.Execute;
  Pfad := UTF8ToSys(OpenDialog1.FileName);
  option := [rfReplaceAll, rfIgnoreCase];
  AusNamePfad := StringReplace(Pfad,'szf','txt',option);
  AssignFile(Datei,Pfad);
  Reset(Datei);
  AssignFile(Ausgabe,AusNamePfad);
  Rewrite(Ausgabe);
  repeat
    Readln(Datei,Zeile);
    wo := Pos(Herst,Zeile);
    if wo >0 then
    begin
      Teil := Copy(Zeile,wo+15,18);
      Teil := StringReplace(Teil,'"','',option);
      writeln(Ausgabe,Trim(Teil));
    end;
  until EOF (Datei); ;
  CloseFile(Datei);
  CloseFile(Ausgabe);
  Label1.Caption := 'Fertig!';
  Label1.Font.Color:=clGreen;
end;
Hier habe ich zwar ALLE Fzg-Hersteller, also auch die deren Datensätze ohne VIN-Abfrage erzeugt wurden aber das ist wurscht. So viele sind das nicht.
Die Textdatei öffne ich in OOCalc oder Excel und mit einer Pivotabelle bekomme ich die jeweiligen Anzahl der Fahrzeuge Heraus. Das genügt mir.
Man könnte vielleicht noch eine Routine basteln um OOCalc oder Excel zu starten, bzw. mit einem Excel- oder OOCalc-Makro aus dem jeweiligen Workbook heraus das Lazarus-Programm zu starten um dann die Daten in die Spalte "A" der Tabelle zu schreiben und die Spalte "B" mit Einsen zu füllen damit die Pivot-Geschichte auch funzt, aber das sind Hirngespinste.

Zumindest muss mein Kollege jetzt nicht mehr mit dem Stift vor dem Monitor sitzen, Datensätze zählen und diese mit der Rechnung über die VIN-Abfragen abgleichen.

Dank an die Mitglieder im Forum

Gruß

Volker

Benutzeravatar
theo
Beiträge: 10872
Registriert: Mo 11. Sep 2006, 19:01

Re: Zugriff auf Textdatei mit TStringList

Beitrag von theo »

Die Frage bleibt: Warum hast du uns überhaupt gefragt? :wink:

schnullerbacke
Beiträge: 1187
Registriert: Mi 13. Dez 2006, 10:58
OS, Lazarus, FPC: Winux (L 1.2.xy FPC 2.6.z)
CPU-Target: AMD A4-6400 APU
Wohnort: Hamburg

Re: Zugriff auf Textdatei mit TStringList

Beitrag von schnullerbacke »

Mach doch auch aus dem Grunsgerüst gleich nen richtigen Scanner. Dann kannst du noch verschiedene Paramter setzen und das Dingens zerlegen wie es gerade nötig ist. Ich nehm mal an, die Datei hat innerhalb der Zeilen einen Feldtrenner, dann lässt sich sowas prima lösen.
Humor ist der Knopf, der verhindert, daß uns der Kragen platzt.

(Ringelnatz)

ErnstVolker
Beiträge: 353
Registriert: Di 17. Feb 2009, 10:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Zugriff auf Textdatei mit TStringList

Beitrag von ErnstVolker »

Na ja gefragt habe ich deshalb, weil ich wissen wollte ob man dieses Problem der Stringbehandlung irgendwie elegant lösen kann.

Ich dachte es kommen Antworten wie: Nimm anstelle von TStringList besser TStringStream oder TMemoryStream.
Darin gibt es die Funktion "xyirgendwas" an die übergibst du einen Suchstring und der liefert Dir dann ...

Leztendlich hab' ich es durch Ausprobieren, google, Forumssuche, Klassen durchstöbern, Lazarus und FPC Buch versucht selbst zu lösen.
Ich war das Nachdenken leid, deshalb gebe ich mich mit der zweitbesten Lösung zufrieden (eigentlich nicht meine Art).

Aber man kann das Ding ja bis zum Sangt Nimmerleinstag ausweiten, wenn man will.

An sich perfekt wäre es, wenn es nicht nur die Fahrzeuge mit VIN_Daten wegschreiben sondern zählen könnte, so wie später die PIVOT-Tabelle.
Da wählt man dann Volkswagen und bekommt meinetwegen 12 Stück. Oder Mazda 3 Stück usw. Dann kann man das mit der Anzahl auf der Monatsrechnung vergleichen und hat die Rechnung geprüft.
Dann könnte die Tabellenkalkulation außen vor bleiben.

Aber ich will es mal nicht übertreiben...

Gruß

Volker

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6780
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Zugriff auf Textdatei mit TStringList

Beitrag von af0815 »

Allgemeinde Frage zu deinem Problem: Wieviele Klassifikationsbegriffe wie 'DATRKAKT', 'DATRKTBA', ... etc gibt es. Sind alle mit '-START' und '-END' eindeutig begrenzt ? Welche nicht begrenzten wie 'KAFH_HST_BENN_K' gibt es ? Oder ist in dem Beispiel alles enthalten ?
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

ErnstVolker
Beiträge: 353
Registriert: Di 17. Feb 2009, 10:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Zugriff auf Textdatei mit TStringList

Beitrag von ErnstVolker »

Also die Datei kann aus sagen wir mal 114 Autos bestehen (Dezember 2011).

Jedes Auto fängt mit: "DATRKAKT-START" an und hört mit: "DATRKAKT-END" auf. Die beiden Begrenzer sind auch jeweils die Einzigen die nicht eingerückt sind.

Dazwischen finden sich KAFH_HST_BENN_K "Mercedes-Benz" und danach KTBA_NAME "VIN_DATEN ".
Die Bezeichner "KAFH_HST_BENN_K" und "KTBA_NAME" sind mehrfach vorhanden, aber für jedes Auto immer nur einmal.

Von der Logik her müsste die Vorgehensweise so sein, dass man nachsieht wo ein Auto anfängt also bei "DATRKAKT-START" und wo es aufhört, bei "DATRKAKT-END" Diese Positionen merken.
Dann in diesem Intervall nach KAFH_HST_BENN_K suchen und nach KTBA_NAME "VIN_DATEN ". Wenn "KTBA_NAME" das Wort VIN_DATEN enthält, dann zurück nach KAFH_HST_BENN_K springen, den Hersteller herauskopieren und wegschreiben. Der Abstand zwischen KAFH_HST_BENN_K und "Mercedes-Benz" ist immer gleich (3 Leerzeichen zwischen K und den Gänsefüßchen). Den Abschnitt zum Herausschneiden kann man ruhig 20 Zeichen breit wählen. Leerstellen werden anschließend mit Trim gestrippt.

Anschließend weiter zum nächsten DATRKAKT-START und das nächste Fahrzeug durchsuchen. Bis EOF erreicht ist.

Gruß und Danke

Volker

schnullerbacke
Beiträge: 1187
Registriert: Mi 13. Dez 2006, 10:58
OS, Lazarus, FPC: Winux (L 1.2.xy FPC 2.6.z)
CPU-Target: AMD A4-6400 APU
Wohnort: Hamburg

Re: Zugriff auf Textdatei mit TStringList

Beitrag von schnullerbacke »

Ich würde das eher in Form eines Scanners lösen,

die Zeichen vom Anfang der Zeile an einlesen und be erreichen eines Terminators(z.B. "="-Zeichen) prüfen obe das gefundene Wort ein Paramtername ist und ob dieser ausgewertet werden soll. Wenn das ja wird der Wert nach "=" eingelesen und verarbeitet, weiterlesen bis zum nächsten Parameternamen sonst. Alles was nicht ausgerwertet werden soll wird verworfen.

Dazu baut man was mit End of Line oder High(stringvar):

Code: Alles auswählen

while not i = High(stringvar) do begin
  inc(i);
  // nächste Zeichen einelesen und prüfen ob Terminator
  term := stringver[i + 1];
  if term in Termlist then begin
    // Status des Automaten prüfen, z.B. ob er gerade einen Wert einliest
  end
  else
    // auf Ende des Strings prüfen, weiterzählen sonst
    param := param + term;
    if param in Paramlist then begin
      // auf's Häufchen getrippelt, Marsch, Marsch
    end;
  end; 
end;
Und das solange wiederholen bis alle Zeilen verabeitet sind. Da hat man dann Möglichkeiten ohne Ende und die Hauptarbeit für den Programmierer sind die Entscheidungen was mit gefundenen Parametern und Werten passieren soll. :D
Humor ist der Knopf, der verhindert, daß uns der Kragen platzt.

(Ringelnatz)

Antworten