Entwickler-Ecke

Sonstiges (Delphi) - Daten in einer txt Datei neu anordnen! *argh*!


LuckyStrike4life - Mo 22.09.03 11:24
Titel: Daten in einer txt Datei neu anordnen! *argh*!
Morgen,

ja - also es geht wieder mal um Daten.
Mir wurde eine 35,6 MB Große txt Datei gegeben und ich soll die Anordnung verändern. Es handelt sich bei den Daten um GPS vermessungen. Hier mal n kleiner Auszug:
Zitat:
11.2500000000 53.7500000000 94
11.2502777778 53.7500000000 94
11.2505555556 53.7500000000 93
11.2508333333 53.7500000000 93
11.2511111111 53.7500000000 92
11.2513888889 53.7500000000 91
11.2516666667 53.7500000000 91
11.2519444444 53.7500000000 92
11.2522222222 53.7500000000 90
11.2525000000 53.7500000000 90
11.2527777778 53.7500000000 89
11.2530555556 53.7500000000 90
11.2533333333 53.7500000000 90
11.2536111111 53.7500000000 90
11.2538888889 53.7500000000 89
11.2541666667 53.7500000000 88
11.2544444444 53.7500000000 89
11.2547222222 53.7500000000 92
11.2550000000 53.7500000000 94
11.2552777778 53.7500000000 94
11.2555555556 53.7500000000 92
11.2558333333 53.7500000000 88
11.2561111111 53.7500000000 86
11.2563888889 53.7500000000 86
11.2566666667 53.7500000000 86
11.2569444444 53.7500000000 85
11.2572222222 53.7500000000 84
11.2575000000 53.7500000000 83


Jetzt zu dem richtigen Problem. Die ersten Zahlen (angefangen bei "11." bis zum Freizeichen) stehen für "x" die nächsten Zahlen (von "53" bis Freizeichen) für y und die letzten beiden stehen für "z".
So kann man damit im Matrixsystem arbeiten. Nun ist die Reihenfolge "x, y, z" aber nicht zugebrauchen sondern "y, x, z" wird benötigt.

Das heißt ich muss die erste Spalte mit der zweiten Spalte vertauschen. Und dann wieder als txt Datei ausgeben.

Habt ihr Ideen?


barfuesser - Mo 22.09.03 11:43

[no delphi]
gib mal unter Linux auf der Konsole folgende Zeile ein:

Quelltext
1:
gawk '{ print $2 " " $1 " " $3 }' old.dat > new.dat                    

old.dat - alte Datei
new.dat - die neue Datei mit der neuen Reihenfolge der Daten
Es könnte auch sein, daß Du statt gawk nur awk aufrufen mußt.
[/no delphi]

barfuesser


lambruco - Mo 22.09.03 11:51

Zeilenweise einlesen,
vertauschen
und schreiben.
Wo liegt das Problem ??
readln,writeln ein wenig stringverarbeitung.

Folgende Funktion könnte dir helfen:
(Bsp: Token(Zeile,' ',2) gibt dir den zweiten Eintrag (53.xxx)).


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
function Token(sString : string; sDelim : string;
               nTokenNo : longint) : string;
var
  sWork      : string;
  sToken     : string;
  nStringLen : longint;
  nDelimLen  : longint;
  nDelimPos  : longint;
  i          : longint;
begin
  sWork := sString;
  nStringLen := Length(sString);
  nDelimLen  := Length(sDelim);
  for i := 1 to nTokenNo do
    begin
      nDelimPos := Pos(sDelim, sWork);
      if nDelimPos = 0 then nDelimPos := Length(sWork) + 1;
      sToken := Copy(sWork, 1, nDelimPos-1);
      sWork := Copy(sWork, nDelimPos + nDelimLen, nStringLen)
    end;
  Token := sToken;
end;


barfuesser - Mo 22.09.03 11:57

[ot]
Wenn ich die letzten beiden Postings vergleiche, weiß ich warum ich Linux und seine Tools so mag!
[/ot]

barfuesser


LuckyStrike4life - Mo 22.09.03 12:07

lambruco hat folgendes geschrieben:
Zeilenweise einlesen,
vertauschen
und schreiben.
Wo liegt das Problem ??
readln,writeln ein wenig stringverarbeitung.

Folgende Funktion könnte dir helfen:
(Bsp: Token(Zeile,' ',2) gibt dir den zweiten Eintrag (53.xxx)).


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
function Token(sString : string; sDelim : string;
               nTokenNo : longint) : string;
var
  sWork      : string;
  sToken     : string;
  nStringLen : longint;
  nDelimLen  : longint;
  nDelimPos  : longint;
  i          : longint;
begin
  sWork := sString;
  nStringLen := Length(sString);
  nDelimLen  := Length(sDelim);
  for i := 1 to nTokenNo do
    begin
      nDelimPos := Pos(sDelim, sWork);
      if nDelimPos = 0 then nDelimPos := Length(sWork) + 1;
      sToken := Copy(sWork, 1, nDelimPos-1);
      sWork := Copy(sWork, nDelimPos + nDelimLen, nStringLen)
    end;
  Token := sToken;
end;

Aha,
also würde ich die Datei ganz normal laden lassen und dein Code auf ne OnpressButton Funktion legen.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
procedure TMainForm.Button1Click(Sender: TObject);
begin

  
  SL := tStringList.Create;

  Try
    SL.LoadFromFile ('c:\file.txt');
    
    begin

[...]Dein Code [...]

    end;
  Finally
    SL.Free;
  end;
end;


Aber leider geht mir dein Code nicht so ganz auf, könntest du ihn mir mal etwas erläutern, damit ich weiß wo genau ich eingreifen und verändern muss?

@barfuesser
Zitat:
[no delphi]
gib mal unter Linux auf der Konsole folgende Zeile ein:
Code:
gawk '{ print $2 " " $1 " " $3 }' old.dat > new.dat

old.dat - alte Datei
new.dat - die neue Datei mit der neuen Reihenfolge der Daten
Es könnte auch sein, daß Du statt gawk nur awk aufrufen mußt.
[/no delphi]

barfuesser

Linux hab ich leider hier auf Arbeit nicht, könnte ich aber zuhause ausprobieren.
Aber obs dann funktionieren wird, hm.. wie muss ich denn dann die neue Reihenfolge angeben?


lambruco - Mo 22.09.03 12:25

Ähem...
ein bisschen mehr musst du schon machen.
Deine Textdatei musst du zeilenweise einlesen: Stichwort readln
Du erhältst einen String, der genau einer Zeile entspricht.
Mit Hilfe der Funktion Token kannst du den String zerlegen


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
var
  x,y,z : String;
begin
  x := Token (Zeile,' ',2// gibt dir den zweiten Teil, also 53.xxx
  y := Token (Zeile,' ',1)// gibt dir den ersten Teil, also 11.xxx
  z := Token (Zeile,' ',3)// gibt dir den ersten Teil, also 83 o.s
  result := y + ' ' + x + ' ' + z;
end;


Anschliessend kannst du das Ergebnis in eine neue Textdatei schreiben:
Stichwort append, writeln

Ruhig mal die Hilfe von Delphi bemühen oder schick 50€, dann tipp ich es dir auch noch.


LuckyStrike4life - Mo 22.09.03 12:28

Okay Leude,

ich glaub mir ist heute mal selber die Lösung eingefallen. Umständlich, aber es geht.

Ich werde das Programm so schreiben, dass jede Zeile erkannt wird, und nach bestimmten Mengen an vergangenen Zeichen die Zahlen ausgelesen und in eine dBase Tabelle geschrieben werden.
Nun, ne dBase Datei ist keine txt Datei aber man kann sie in Excel einlesen lassen und dann als txt Datei ausgeben lassen.

Umständlich, aber es wird gehen :D . Bin ja mal froh das mir auch ab und zu selber ne Lösung einfällt.

Dennoch vielen Dank!


CenBells - Mo 22.09.03 12:28

HAllo LuckyStrike4Life,

also, was hast du aus der letzten aufgabe gelernt?

LuckyStrike4Life hat folgendes geschrieben:
Wie ist es zu realesieren das alle Zeilen abgearbeitet werden. Schon klar das ich dafür eine Schleife brauche ... allerdings ist mir nicht klar wie dies umzusetzen ist.


Also kommst du mit deinem bisherigen ansatz

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
  SL := tStringList.Create; 

  Try 
    SL.LoadFromFile ('c:\file.txt'); 
     
    begin 

[...]Dein Code [...] 

    end
  Finally 
    SL.Free; 
  end
end;


nicht weiter. Dann verarbeitest du wieder nur eine Zeile.
Der Code von lambruco liefert dir, mit dem entsprechenden aufruf (bsp hat er angegeben), immer die koordinatenzahl - entweder x: ntoken=1 etc.
Was du also brauchst ist eine Schleife, dir nach dem laden in die stringlist alle items durchgeht.


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:
function Token(sString : string; sDelim : string
               nTokenNo : longint) : string
var 
  sWork      : string
  sToken     : string
  nStringLen : longint; 
  nDelimLen  : longint; 
  nDelimPos  : longint; 
  i          : longint; 
begin 
  sWork := sString; 
  nStringLen := Length(sString); 
  nDelimLen  := Length(sDelim); 
  for i := 1 to nTokenNo do 
    begin 
      nDelimPos := Pos(sDelim, sWork); 
      if nDelimPos = 0 then nDelimPos := Length(sWork) + 1
      sToken := Copy(sWork, 1, nDelimPos-1); 
      sWork := Copy(sWork, nDelimPos + nDelimLen, nStringLen) 
    end
end;
...


...
var
  LTempStr: String;
  LRowNr: Integer;
begin
  SL := tStringList.Create; 

  Try 
    SL.LoadFromFile ('c:\file.txt'); 
    for LRowNr := 0 to sL.count - 1 do begin 
      SL[LRowNr] := Token(SL[LRowNr], ' '2) + ' ' +
        Token(SL[LRowNr], ' '1) + ' ' +
        Token(SL[LRowNr], ' '3);
    end
   SL.saveToFile('C:\file2.txt');
  Finally 
    SL.Free; 
  end
end;


Gruß
Ken


CenBells - Mo 22.09.03 12:29

edit: Sorry, war ein doppelpost
edit2: Super, ganze arbeit umsonst :evil:


lambruco - Mo 22.09.03 12:34

Würde klappen, aber eine Stringliste mit knapp 40 MB ??
Könnte ein bißchen schwerfällig sein, oder ?


CenBells - Mo 22.09.03 12:38

lambruco hat folgendes geschrieben:
Würde klappen, aber eine Stringliste mit knapp 40 MB ??
Könnte ein bißchen schwerfällig sein, oder ?


Von leichtfüssigem code war auch keine rede 8) :lol:

Ich würde es wohl auch mittels readln und writeln lösen, aber er wollte nun mal wieder mit ner stringlist arbeiten *G*

Gruß
KEn


barfuesser - Mo 22.09.03 12:40

LuckyStrike4life hat folgendes geschrieben:
wie muss ich denn dann die neue Reihenfolge angeben?

Wie oben angegeben! Bei awk ist der RecordSeparator auf ein Leerzeichen voreingestellt. in $0 steht die gesamte Zeile, in $1 die erste Spalte, in $2 die zweite usw. Mit 'print $2 $1 $3' werden also die 3 Spalten in der von Dir gewünschten Reihenfolge ausgegeben. Sie stehen dann aber ohne Trennzeichen hintereinander. Deshalb habe ich in obigen Code wieder jeweils ein Leerzeichen eingefügt. Nun die Ausgabe in eine neue Datei umleiten und fertig bist Du. Wie Du sehen kannst ein wunderschöner kleiner Einzeiler. Und die Zeit, die er eventuell während der Ausführung länger als ein compiliertes Programm benötigt, sparst Du locker bei der "Programmierung"!

Übrigens gibt es mit den CygWin-Tools eine komplette Linux-Shell für Windows, bei der die ganzen schönen Tools von awk über perl bis sed vorhanden sind.

barfuesser


smiegel - Mo 22.09.03 14:11

Hallo,

wie wäre es damit?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
procedure Tausche;
var tin, tout:Textfile;
    lese:String;
begin
  AssignFile(tin, 'c:\quelle.txt');
  AssignFile(tout, 'c:\ziel.txt');
  Reset(tin);
  Rewrite(tout);
  while not Eof(tin) do
  begin
     ReadLn(tin, lese);
     WriteLn(tout, Copy(lese, 1513), ' ', Copy(lese(113), ' '
                   Copy(lese, 29, Length(lese)-28));
  end// while
  CloseFile(tout);
  CloseFile(tin);
end// Tausche;


Der Code geht von der Annahme aus, dass die Länge der x- und y-Koordinaten gleich lang ist (13 Zeichen).


LuckyStrike4life - Mo 22.09.03 14:11

CenBells hat folgendes geschrieben:
edit: Sorry, war ein doppelpost
edit2: Super, ganze arbeit umsonst :evil:


Vielen Dank, CenBells -

du bist immer sogut und weise zu mir. Eventuell komme ich auch noch auf deinen Code zurück!

Werde jetzt mal die Linux Lösung von Barfuesser probieren, wenn denn mein Arbeitsrechner Knoppix frist. Hab meine Mittagspause extra genutzt um nach hause zu fahren und Knoppix zu suchen.

Was ich noch gerne wissen würde, wie kann ich in einer Schleife, die eine IF Anweisung ausführt - zwei Bedingungen ablaufen lassen? D.h. wenn die IF mit ja beantwortet wird, sollen mehrere Dinge abgearbeitet werden.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
For Idx := 0 To SL.Count -1 Do
    begin

     If Copy (Sl[Idx], 12) = '11' Then begin
     gesuchterWert := copy(sl[idx], 015);
     xyztabelle.Append;
     xyztabelle.FieldByName('x').AsString := gesuchterWert;
     xyztabelle.Post;

    end;

Also es müsste nochmals

Delphi-Quelltext
1:
2:
3:
4:
     gesuchterWert := copy(sl[idx], 015);
     xyztabelle.Append;
     xyztabelle.FieldByName('x').AsString := gesuchterWert;
     xyztabelle.Post;
kommen. Natürlich in leicht abgeänderter Form, sonst würde es kaum sinn machen.

Könnte mir das mal jemand verraten?


smiegel - Mo 22.09.03 14:14

Irgendwie ging gerade etwas mit einem nächträglichen Edit in die Hose. Diese Eintrag bitte löschen.


LuckyStrike4life - Mo 22.09.03 14:48

smiegel hat folgendes geschrieben:
Hallo,

wie wäre es damit?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
procedure Tausche;
var tin, tout:Textfile;
    lese:String;
begin
  AssignFile(tin, 'c:\quelle.txt');
  AssignFile(tout, 'c:\ziel.txt');
  Reset(tin);
  Rewrite(tout);
  while not Eof(tin) do
  begin
     ReadLn(tin, lese);
     WriteLn(tout, Copy(lese, 1513), ' ', Copy(lese(113), ' '
                   Copy(lese, 29, Length(lese)-28));
  end// while
  CloseFile(tout);
  CloseFile(tin);
end// Tausche;


Der Code geht von der Annahme aus, dass die Länge der x- und y-Koordinaten gleich lang ist (13 Zeichen).


Ahhh Sniegel!

Das ist richtig! Du bist mein Held!! Danke, vielen Dank!

Auch bei den anderen bedanke ich mich. Sehr geht, Leute! Ich mag eure Bereitschaft zur Hilfe!!

Und natürlich mein dicken Respekt an Sniegel, vielleicht sollte ich mich Sniegel4life nennnen? :D

Na dann, bis bald!


smiegel - Mo 22.09.03 15:57

Hallo LuckyStrike4life,

Danke für das Lob.

Bloss ist Dir ein kleiner Fehler unterlaufen: ich nenne mich Smiegel und nicht Sniegel ;-)