Parser pliku txt

Odpowiedz Nowy wątek
2011-08-23 15:55
0

Mam dany plik w następującym formacie:

-KSBLOZ-------NazwaTowaru---------------------------------CenaTrans-VAT-
 116590111009 Vit. A kaps. 12,000 j.m. 50 szt.                1.55   2
 116590311057 Vit. A plyn 50.000 j.m./1ml 10 ml               1.00   2
 119530111009 Vit. A+D3 (2000j.m.A+1000j.m kaps. 50 szt.      1.55   2
 119530311057 Vit. A+D3 solutio aquosa krople 10ml            1.00   2

Moim zadaniem jest stworzenie zestawu klas do operacji na nim, ale za cholerę nie wiem jak się do tego zabrać.

Ilość kolumn może być większa, przedstawiony plik prezentuje jedynie format. Nazwy kolumn i ich ilość będą się zmieniać. To co udało mi się zrobić to opracować algorytm do zliczania ilości kolumn w pliku oraz ich długości (ilość znaków w nazwie oraz liczba "-" determinują max ilość znaków dla poszczególnej kolumny).

Jedyne na co wpadłem to zapisanie tych informacji w tablicy, co jednak nie jest perfekcyjne gdyż do momentu zliczenia kolumn nie wiem jak duża potrzebna mi jest tablica. Może jest coś odpowiadającego ArrayList z javy?

Nie oczekuje gotowego rozwiązania ale potrzebuje jakichś wskazówek odnośnie wykonania tego zadania, to dla mnie bardzo ważne.

Pozdrawiam

edytowany 1x, ostatnio: JacekKw, 2011-08-23 15:55

Pozostało 580 znaków

2011-08-23 16:02
1

Jedyne na co wpadłem to zapisanie tych informacji w tablicy, co jednak nie jest perfekcyjne gdyż do momentu zliczenia kolumn nie wiem jak duża potrzebna mi jest tablica. Może jest coś odpowiadającego ArrayList z javy?

var
a:array of array of ansistring;
i,j:integer;
 
setlength(a,2);
setlength(a[0],2);
setlength(a[1],2);
for i:=0 to length(a)-1 do for j:=0 to length(a[i])-1 do a[i,j]:='cos';

A co do reszty - co to za problem użyć Pos, copy, i paru innych funkcji?


Nie pisz do mnie PM o czymś co nie dotyczy bezpośrednio mnie. | Nie rozmawiaj ze mną jeśli brak Ci kultury (wystarczy że mi brakuje) | Nie jestem zły, jestem po prostu zły.

Pozostało 580 znaków

2011-08-23 16:24
0

setlength(a,2); //tu deklarujesz długość tablicy a do 2 elementów

setlength(a[0],2); //co się dzieje w tych punktach? Pod a[0] znajduje się kolejna 2-elementowa tablica?
setlength(a[1],2);

Nie słyszałeś o tablicach wielowymiarowych? przecież: a:array of {1} array of {2} ansistring; = Dwuwymiarowa tablica dynamiczna ansistringów... - payl 2011-08-23 17:26

Pozostało 580 znaków

2011-08-23 16:52
1

hint: własną klasę dziedziczącą po TStringList (albo i nie dziedziczącą ale mającą zmienną prywatną tego typu) i automagicznie (czyli zaszyte w kodzie klasy) rozpoznającą i dzielącą pojedynczą linijkę tekstu zapakować we własną klasę dziedziczącą po TObjectList (moduł contnrs) z metodami do odczytu pliku, wyciągania nazw kolumn oraz długości poszczególnych pól i dodawania poszczególnych linii do klasy dziedziczącej po TStringList. Jak to dobrze rozplanujesz to dodanie nowego szablonu pliku nie będzie wymagało od Ciebie ani jednego znaku kodu do napisania.
Tablica dynamiczna tablicą dynamiczną ale po co sobie utrudniać życie jak TStringList daje Ci wygodne operowanie na liście stringów


- Ciemna druga strona jest.
- Nie marudź Yoda, tylko jedz tego tosta.
Google NIE GRYZIE!
Pomogłem - kliknij

Pozostało 580 znaków

2011-08-23 19:10

@misiekd fajnie Cie znowu czytać :P

podążałem za Twoimi wskazówkami odnośnie TStringList. Wkleję fragmencik kodu:

  begin    
    AssignFile(TF, 'G:\\test.txt');
    Reset(TF);
 
    Readln(TF, S);
    names:=TStringList.Create;
    names.Delimiter := '-';
    //names.QuoteChar := '-';
    names.DelimitedText := S;
 
    for i := 0 to names.Count - 1 do showmessage(names[i]);
 
  end;

Wziąłem na początek pod uwagę jedynie pierwszą linię pliku.
To jednak wyświetla mi między dobrze pobranymi nazwami nagłówka puste komunikaty. Podejrzewam, że to puste miejsca pomiędzy kolejnymi znakami -
Może jest sposób żeby się ich pozbyć?


EDIT:
Ależ ze mnie bęcwał. Wystarczyło dodać do pętli warunek:

    for i := 0 to names.Count - 1 do
      begin
        if names[i]<>'' then showmessage(names[i]);
      end;

Z drugiej strony może jest "higieniczniejsze" rozwiązanie, które nie zapisywałoby mi pustych pól do StringListy? (oczywiście w pętli moge przerzucic już do nowej stringlisty tylko istotne pola)

edytowany 3x, ostatnio: JacekKw, 2011-08-23 19:37

Pozostało 580 znaków

2011-08-23 22:18
0

Niemal bym skończył gdyby nie jeden zasadniczy problem:

-KSBLOZ-------NazwaTowaru---------------------------------CenaTrans-VAT-
 116590111009 Vit. A kaps. 12,000 j.m. 50 szt.                1.55   2
 116590311057 Vit. A plyn 50.000 j.m./1ml 10 ml               1.00   2
 119530111009 Vit. A+D3 (2000j.m.A+1000j.m kaps. 50 szt.      1.55   2
 119530311057 Vit. A+D3 solutio aquosa krople 10ml            1.00   2

Przy pobieraniu rekordów poniższy kod się nie sprawdza:

            values:=TStringList.Create;
            values.Delimiter := ' ';
            values.DelimitedText := S;

Jak widzicie w nazwie towaru występują spację, które powodują rozdzielanie danych do różnych pozycji na liście. Jakieś obejście?

Pozostało 580 znaków

2011-08-24 09:47
1

ale to nie tak! Najpierw musisz wyciągnąć z pierwszej linii takie dane jak
nazwa kolumny chociaż jak Ci to nie potrzebne to możesz olać
długość kolumny
i tak dla wszystkich kolumn
Wyciągnięcie liczby kolumn i długości każdej powinieneś mieć w klasie głównej.

Metoda ParsujPlik (czy jak sobie ją nazwiesz) w klasie głównej powinna wyglądać mniej więcej tak

function TKlasaGlowna.ParsujPlik(Plik: string): Boolean
var
  sl: TStringList;
begin
  sl.LoadFromFile(Plik);
  WyodrebnijKolumny(sl[0]);
  for i := 1 to sl.Count - 1 do
    TKlasaRekord.Create(FKolumny, sl[i]); //FKolumny to coś (np. tablica dynamiczna) z opisem kolumn, który powstaje w metodzie WyodrebnijKolumny
end;
 
//FPola to np. TStringList z listą wartości w poszczególnych polach
constructor TKlasaRekord.Create(AKolumny: TKolumny; l: string)
begin
  for i := 0 to Length(AKolumny) - 1 do
  begin
    FPola.Add(Copy(l, 1, AKolumny[i].Dlugosc_kolumny));
    Delete(l, 1A, Kolumny[i].Dlugosc_kolumny);
  end;
end;

Sama klasa TStringList nie wyciągnie za ciebie danych z poszczególnych linii i nie porozbija ich - tego nie da się załatwić delimiterem ponieważ w danych źródłowych taki nie istnieje.
Z drugiej strony jak zrobisz to tak jak proponuję to jeśli dojdzie Ci w pliku nowa kolumna, zmieni się ilość znaków w kolumnie czy cokolwiek innego to nie będzie to miało znaczenia - jeśli nagłówek (czyli pierwsza linia) będzie poprawny w stosunku do reszty danych to zawsze zadziała Ci to prawidłowo. Także wyświetlanie czy obróbka sparsowanych danych nie będzie problemem


- Ciemna druga strona jest.
- Nie marudź Yoda, tylko jedz tego tosta.
Google NIE GRYZIE!
Pomogłem - kliknij

Pozostało 580 znaków

2011-08-24 13:01
0

Trochę się pogubiłem

Rozumiem, że ma być:

Delete(l, 1, AKolumny[i].Dlugosc_kolumny);

Jeśli chodzi o ta linijkę:

FPola.Add(Copy(l, 1, AKolumny[i].Dlugosc_kolumny));

Dlugosc_kolumny to funkcja zadeklarowana w klasie TKolumny?

Pozostało 580 znaków

2011-08-24 13:09
0

Najpierw musisz wyciągnąć z pierwszej linii takie dane jak
nazwa kolumny chociaż jak Ci to nie potrzebne to możesz olać
długość kolumny

/FKolumny to coś (np. tablica dynamiczna) z opisem kolumn, który powstaje w metodzie WyodrebnijKolumny


- Ciemna druga strona jest.
- Nie marudź Yoda, tylko jedz tego tosta.
Google NIE GRYZIE!
Pomogłem - kliknij

Pozostało 580 znaków

2011-08-24 13:21
0

/FKolumny to coś (np. tablica dynamiczna) z opisem kolumn, który powstaje w metodzie WyodrebnijKolumny

Jak przekazać tablice jako wynik funkcji? tzn z tego co się orientuje jest to niemożliwe.

Pozostało 580 znaków

2011-08-24 13:26
1

dokładnie tak samo jak każdą inną zmienną

type
  TJakasTablica = array of cokolwiek;
 
function JakasSUperZajebistaFunkcja: TJakasTablica
begin
  SetLength(Result, 10);
  Result[0] := Cokolwiek;
end;

- Ciemna druga strona jest.
- Nie marudź Yoda, tylko jedz tego tosta.
Google NIE GRYZIE!
Pomogłem - kliknij
czyli opakowaną w obiekt - JacekKw 2011-08-24 13:29
Jacek Ty sam jak obiekt jesteś! Podstawy poczytaj - Misiekd 2011-08-24 13:37

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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