Wczytanie do tabeli pliku nr,x,y

0

Witam.
Nie mam wielkiej wiedzy z pascala, a jedynie potrafię stworzyć kilka narzędzi potrzebnych do pracy. Tym razem potrzebuje wczytać do tabeli plik o strukturze Nr X Y np:

p123 1000.02 1000.01
o2 1471.21 4894.19

gdzie nr:string o nieznanej długości, a x,y:real. Może też być inny niż ' ' rozdzielacz. Nie mam problemu z wczytaniem pliku o strukturze X Y Nr (z użyciem pętli z Pos i Delete), ale nie wiem jak sobie poradzić, kiedy string jest pierwszy i żeby program rozpoznał koniec stringa i zaczął wczytywać liczby rzeczywiste. Szukałem rozwiązania, ale najczęściej dane w pliku są jednego typu (liczba albo string).

wersja procedury dla XYN wygląda u mnie tak:

procedure wczytaj;
var
  c: integer;
begin
  i := 0;
  assign(f, 'xyn.txt');
  reset(f);
  
  while not eof (f) do
  begin
    i := i + 1;
    readln(f, d[i].x, d[i].y, d[i].spac, d[i].n);
  end;
  
  close(f);
  j := i;
  ilp := j;
  
  for i := 1 to j do
  begin
    c := Pos(' ', d[i].n);
    
    repeat
    begin
      Delete(d[i].n, c, 1);
      c := Pos(' ', d[i].n);
    end;
  until c = 0;
end;
1

Ja na twoim miejscu użyłbym TStringList i funkcji ExtractStrings
dzięki temu w stringliście (TStringList) będziesz miał 3 pola oddzielone separatorami jakie sobie zdefiniujesz w extractstrings. X i Y pozostaje tylko przekonwertować na real lub nawet napisać sobie specjalną klasę/helper do TStringList, która załatwi to za ciebie.

0

Zastanawiałem się nad tym rozwiązaniem dziś rano, tylko nie przyglądałem się jeszcze na ile takie konwertowanie string to real jest skomplikowane. Ale może to jest ten kierunek

1

Dane wejściowe są na tyle niejednorodne, że standardowym sposobem nie można ich wczytać; Głównie ze względu na pierwszy człon, który może być dowolnej długości i jednocześnie nie jest to liczba; Dlatego też trzeba linię wczytać w całości (jako łańcuch znaków), rozdzielić na składowe i przekonwertować na natywne dane (jeśli o liczby chodzi);

Najprostszym sposobem jest jak zwykle ExtractStrings - utworzyć pomocniczą listę i ładnie sobie wszystko podzielić; Można też samemu podłubać i ręcznie wyodrębnić fragmenty danej linii; Ciekawym sposobem jest zamiana separatorów (spacji) na znaki NULL i skorzystanie ze wskaźnika na bieżący znak ciągu oraz funkcji StrPas i StrLen;

W ramach ciekawostki - przykład pozyskania fragmentów łańcucha bez konieczności używania pomocniczej listy łańcuchów znaków typu TStringList (link: http://ideone.com/edEkaG):

uses
  SysUtils;

  procedure ShowComponents(const ALine: String);
  var
    strLine: String;
    pchrComp: PChar;
  begin
    strLine := StringReplace(ALine, ' ', #0, [rfReplaceAll]) + #0;
    pchrComp := @strLine[1];

    while pchrComp^ <> #0 do
    begin
      WriteLn('"', StrPas(pchrComp), '"');
      pchrComp += StrLen(pchrComp) + 1;
    end;
  end;

begin
  ShowComponents('p123 1000.02 1000.01');
end.

Na wyjściu otrzymamy:

"p123"
"1000.02"
"1000.01"

Jeśli komuś zależy na szybkości to jest to dobry sposób - dłuższy, ale szybszy; Przy czym funkcja StringReplace też nie grzeszy szybkością, więc ją też można zamienić na własną - szybszą;

Inna sprawa to sama konwersja ciągów znaków na liczby zmiennoprzecinkowe; Może się zdarzyć tak, że znak kropki jako separatora dziesiętnego nie będzie pasował; W takim wypadku trzeba albo zmienić znak separatora na własny lub skorzystać z procedury Val.

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