Wstawianie danych do pliku .txt - separator

0

Witam,

mam na celu stworzyć aplikację, która po wciśnięciu Buttona, z jednego pliku tekstowego, w którym przechowywane są dane w takiej postaci:

aaaaaaa, bbbbbb, cccccc

zapisze dane aaaaaaa, bbbbbbb, ccccccc w trzech innych plikach tekstowych.

Na razie próbuję się uporać z pierwszą kolumną "aaaaaaa", by zapisać ją w pliku. Poniższy program kompiluje się, ale po wciśnięciu przycisku aplikacja się zawiesza, no i oczywiście nie działa jak powinna. Jak to poprawić? :( Zapewne zadanie można rozwiązać różnorako, np. że przecinek potraktować jako separator, ale tak próbowałam i coś tam nie wyszło, więc dałam sobie spokój -.-

procedure TForm1.Button1Click(Sender: TObject);
var
  tablica: array of string;
  f: textfile;
  g: textfile;
  s: string;
  i: integer;

begin

  assignfile(f,'C:\Users\Magda\Desktop\lokalizacje.txt');
  assignfile(g,'C:\Users\Magda\Desktop\miasta.txt');

  reset(f);
  rewrite(g);

  repeat
    begin
      Readln(f,s);
      SetLength(tablica, Length(s));
          for i:=1 to Length(s) do
            begin
              repeat
              Tablica[i] := s[i];
              writeln(g, s[i]);
              until Tablica[i] = ',';
            end;
    end;
  until eof(f);

  closefile(f);
  closefile(g);

end;

Będę wdzięczna za pomoc,
Pozdrawiam :)

2

Wczytaj linię z pliku do zmiennej łańcuchowej, następnie rozłóż linię na składowe za pomocą funkcji ExtractStrings i później już iteruj po elementach listy, wykorzystując jej zawartość.

2

Przecież wystarczy:

while not eof(f) do
begin
  ReadLn(f,s);
  WriteLn(g,s);
end;

Natomiast jeżeli chcesz koniecznie rozdzielać na pola to:

function Parse(var Str:String;const Delimeter:String):String;
var P:Integer;
begin
  P:=Pos(Delimeter,Str);
  if P>0 then
  begin
    Result:=Copy(Str,1,P-1);
    Delete(Str,1,P+Length(Delimeter)-1);
  end
  else
  begin
    Result:=Str;
    SetLength(Str,0);
  end;
end;

while not eof(f) do
begin
  ReadLn(f,s);
  row:=Trim(Parse(s,','));
  WriteLn(g,row);
  while Length(Trim(s))>0 do
  begin
    row:=Trim(Parse(s,','));
    WriteLn(g,'; '+row);
  end;
end;
0

_13th_Dragon - Ty to tak szybko napisałeś? :O

while not eof(f) do
begin
  ReadLn(f,s);
  WriteLn(g,s);
end;

Te rozwiązanie nie pasuje, bo każda "rubryka" musi iść do innego pliku tekstowego.

Funkcja ExtractStrings wydaje się być odpowiednia, w razie jak mi coś nie wyjdzie skorzystam z tej funkcji Parse.

Dzięki bardzo za pomoc :)

1

Pamiętaj że dla ExtractStrings musisz najpierw stworzyć obiekt TStringList i przekazać go zamiast TStrings.
Na końcu zwolnić obiekt TStringList

1

W ramach rozrywki i ciekawostki, przedstawiam najdłuższy i najdziwniejszy algorytm do tego zadania, ale powinien być szybszy od zlepku funkcji Pos, PosEx, Copy/Delete; Moja ulubiona metoda do analizy i ekstrakcji danych z łańcuchów i choć szybka dość szybka, to strasznie długa... :]

Oprócz samego wypakowania podciągów, nie jest wrażliwa na większą ilość znaków separatora pomiędzy podciągami;

  procedure SaveSubStringsToFiles(const ALine: AnsiString; const ADelimiter: AnsiChar);
  var
    pchrBegin, pchrEnd, pchrLast: PAnsiChar;
    fOutput: TextFile;
    strSub: AnsiString;
  begin
    pchrEnd := @ALine[1];
    pchrLast := @ALine[Length(ALine) + 1];

    while pchrEnd < pchrLast do
    begin
      while (pchrEnd < pchrLast) and (pchrEnd^ = ADelimiter) do
        Inc(pchrEnd);

      if pchrEnd < pchrLast then
      begin
        pchrBegin := pchrEnd;
        Inc(pchrEnd);

        while (pchrEnd < pchrLast) and (pchrEnd^ <> ADelimiter) do
          Inc(pchrEnd);

        if pchrBegin <= pchrEnd then
        begin
          SetLength(strSub, pchrEnd - pchrBegin);
          Move(pchrBegin^, strSub[1], pchrEnd - pchrBegin);

          AssignFile(fOutput, 'C:\' + strSub + '.txt');
          ReWrite(fOutput);
          try
            WriteLn(fOutput, strSub);
          finally
            CloseFile(fOutput);
          end;
        end;
      end;
    end;
  end;

var
  fInput: TextFile;
  strLine: AnsiString;
begin
  AssignFile(fInput, 'C:\Input.txt');
  Reset(fInput);
  try
    ReadLn(fInput, strLine);
    SaveSubStringsToFiles(strLine, ' ');
  finally
    CloseFile(fInput);
    WriteLn('done...');
    ReadLn;
  end;
end.

Jeżeli w pliku C:\Input.txt znajdować się będzie jedna linia o treści first second third , to utworzone zostaną pliki:

  • C:\first.txt,

  • C:\second.txt,

  • C:\third.txt
    z zawartością odpowiadającą ich nazwom bez rozszerzenia, czyli:

  • first,

  • second,

  • third;
    To tylko ciekawostka, bo oczywiście krócej i łatwiej zastosować procedury i funkcje z RTL.

0

Trochę mi to zajęło, ale jakoś udało mi się podzielić te dane funkcją ExtractStrings. Podzielone dane wrzuciłam do ListBoxa, są w postaci:

aaaa
bbbb
cccc
aaaa
bbbb
cccc

itd.

Teraz kombinuję, by dane wrzucić do tabeli [StringGrid] tak, aby w pierwszej kolumnie wrzucić dane aaaaa, do drugiej bbbbb, a do trzeciej ccccc. Nie umiem zrobić pętli for, aby iterowała co 3, więc próbowałam zrobić warunek, dla którego w przypadku reszty z dzielenia przez 3 = 1 wrzuć daną do pierwszej kolumny, w przypadku reszty z dzielenia przez trzy = 2 wrzuć do drugiej kolumny, a w przypadku reszty z dzielenia przez trzy = 0 wrzuć do trzeciej kolumny.

Nie wiem co z moimi warunkami jest nie tak ale program totalnie je olewa, tj. traktuje, że przy każdej iteracji spełnione są trzy warunki co w konsekwencji prowadzi do tego, że dane są te wszystkie te same w trzech kolumnach :(

procedure TForm1.Button1Click(Sender: TObject);
var
  slInput: TStrings;
  f: textfile;
  s: string;
  i,j: integer;
  liczba: integer;

begin

  AssignFile(f, 'C:\Users\Magda\Desktop\lokalizacje.txt');
  reset(f);

  slInput := TStringList.Create();

  try
  repeat
    begin
      Readln(f, s);
      s := String(PChar(s));
      ExtractStrings([','], [' '], PChar(s), slInput);
      ListBox1.Items.Assign(slInput);
    end;
  until eof(f);

  Form1.StringGrid1.RowCount := slInput.Count+1;
  slInput.Insert(0, 'Miejscowosc');

  liczba:=0;

     for j:=0 to Form1.StringGrid1.Colcount-1 do
       begin
       for i:=1 to Form1.StringGrid1.Rowcount-1 do
         begin
           liczba:=liczba+1;
           if (liczba mod 3 = 1) then StringGrid1.Cols[0].Assign(slInput);
           if (liczba mod 3 = 2) then StringGrid1.Cols[1].Assign(slInput);
           if (liczba mod 3 = 0) then StringGrid1.Cols[2].Assign(slInput);
         end;
       end;

  closefile(f);

  finally
   slInput.Free();
  end;

end;

Co jest nie tak? :(

1
s := String(PChar(s));

A co to?

Nie sprawdzałem działania takiego kodu, ale tę instrukcję:

ListBox1.Items.Assign(slInput);

wywołujesz ciągle w pętli, więc w kółko kasujesz poprzednią zawartość komponentu i wpisujesz nową, tuż po wywołaniu ExtractStrings; Nowe pozycje dodawaj do komponentu, a nie nadpisuj starych pozycji.

1

Wszystko nie tak. Zadziwia mnie zdolność początkujących robić wszystko w najbezsensowniejszy sposób, przecież wystarczy:

  AssignFile(f, 'C:\Users\Magda\Desktop\lokalizacje.txt');
  try
    reset(f);
    Row:=0;
    StringGrid1.RowCount:=0;
    while not eof(f) do
    begin
      ReadLn(f,s);
      StringGrid1.RowCount:=Row+1;
      StringGrid1.Cells[0,Row]:=Trim(Parse(s,','));
      StringGrid1.Cells[1,Row]:=Trim(Parse(s,','));
      StringGrid1.Cells[2,Row]:=Trim(Parse(s,','));
      Inc(Row);
    end;
  finally
    closefile(f);
  end;
0

Heh, im mniejsza wiedza tym mniejsze pole manewru stąd te dziwactwa ;D Wy znacie pełno przeróżnych funkcji i metod, które ja pierwszy raz na oczy widzę, np. tutaj: Trim i Parse.

Program nie odnajduje mi metody

Parse

Rozumiem, że metoda ta cyt. "Konwertuje ciąg reprezentujący liczbę na odpowiadającą mu liczbę zmiennoprzecinkową pojedynczej precyzji."?

Czy warunek:

while Length(Trim(s))>0 do

mam traktować jako: wykonuj dopóki liczba znaków kontrolnych jest > 0?

1

Trim - funkcja standardowa.
Parse - podałem wyżej.
while Length(Trim(s))>0 do - dopóki w s zostało cokolwiek oprócz białych znaków.
Tak a propos, tamto pisano "z palca" więc już widzę błędy, już poprawiam.

0

Ok dzięki bardzo za poprawki.
Tylko kurde nie odnajduje mi metody Parse..:

Error: Identifier not found "Parse"

Należy załączyć jakąś bibliotekę..?:P

1

Madzu, Madziu! wklej swoj obecny kod to sie poprawi :)
tylko napisz co konkretnie chcesz osiagnac

0

Sorry, ale ze mnie gapa... xD
Nie zauważyłam tej deklaracji . Dzięki ;p

Teraz wszystko gra,
niezmiernie dzięki Wam za pomoc :]

1 użytkowników online, w tym zalogowanych: 0, gości: 1