sposób na wyłuskiwanie danych z plików txt

0

Mam za zadanie wyluskiwac dane z plikow txt eksportowanych do formatu jak nizej:

NazwaFirmy Sp. z o.o. Zamówienie od odbiorcy DZ/0997/14
ul. UlicaFirmy 123 Oryginał
99-999 KodPocztowy Data i miejsce wystawienia: 2013-03-15 Miasto
NIP: 9999999999 Data operacji: 2013-03-15

Biuro rachunkowe
"Nazwa Biura Rachunkowego"" SP. Z O.O.Sp.K."
NIP: 999-999-88-88

Magazyn: Magazyn wyrobów - handlowy 1
Odbiorca:
"Nazwa Odbiorcy ze wszystkimi skrotami"
ul. UlicaOdbiorcy 71 A
99-999 KodOdbiorcy
NIP: 5555555555
Lp. Kod towaru Nazwa towaru Cena Rabat CenaPoRabacie Ilość jm. Wartość

1 fgj23mdjvi4da Nazwa Towaru w systemie ERP 65 0 00% 65 100 szt 6500
Nazwa Rozszerzona 1
2 dmajb93nakeib Normalna Nazwa 12 0 00% 12 20 szt 240

3 3ngkanflow96n Dziwna 328x, nazwa 76 0 00% 76 30 szt 2280

4 gmalburkaje92 Wyrob z grupy o stalej dlugosci nazwy 385 0 00% 385 20 szt 7
Nazwa rozszerzona 2
5 fjka73mpoa825 Wyrob-o-takiej-nazwie 5 0 00% 5 5 szt 25

6 dk239gmajkwo3 Jakis wyrob 6 5 0 00% 5 1 szt 5

  Suma:						9530	
  							
  							
  							

Podsumowanie ilości: 176 szt

Czasami uwagi sa tu
w wielu liniach
Opiekun klienta:
Ilość palet/paczek:
Wysokość palet:
Rodzaj palet:
Materiały reklamowe / reklamacje:
Proponowany termin realizacji:
Informacje dodatkowe/uwagi: a czasami zaczynaja sie tu
i przechodza do kolejnych linii

Sprawdził:

Imie NazwiskoWystawiajacego

.................................................. ..................................................

Podpis osoby uprawnionej do wystawienia dokumentu Podpis osoby upoważnionej do otrzymania dokumentu

SĄD REJONOWY W MIESCIE WYDZIAŁ GOSPODARCZY KRS
©programERP 2013 124.23.10598.579654 sn: 346872159

Interesują mnie dane z tych plików, które wytłusciłem:

  1. Sygnatura dokumentu - pierwsza linia po "Zamówienie od odbiorcy"
  2. Data wystawienia dokumentu - w linii trzeciej, "2013-03-13"
  3. Nazwa Odbiorcy - w linii 12
  4. Wszystkie pozycje zamowienia - konkretnie kolumny: LP, Kod Towaru, Nazwa Towaru, Ilość, jm
  5. Uwagi wpisywane recznie w dwóch róznych lokalizacjach

Pewniki:

  • dokument ma format niezmienny,
  • jedyne co się zmienia to liczba linii pozycji zamowienia i uwagi wystepujace w dwoch lokalizacjach albo nie wystepujace w ogóle.

Moj sposob odczytywania:

  1. sygnatura, data wystawienia i nazwa odbiorcy moge na sztywno przypisac w ktorej linii te dane sa i z ktorej pozycji stringa je brac
  2. pozycje zmowienia:
  • mam taki pomysl aby wszystkie linie ktore wystepuja miedzy liniami zaczynającymi się na "Lp." i "Podsumowanie ilosci:" traktowac jako pozycje zamowienia
  • do pojedynczej pozycji zamowienia dobierac się przez Split'a calej linii po bialych znakach, ale ze w "Nazwa Towaru" tez sa spacje to kolumny "Lp." i "Kod Towaru" odczytywac z tablicy po splicie z pozycji [0] i [1] a pozostale dane pobierac z tablicy po Splicie od konca, z czego "Nazwa towaru" bedzie skladana z pozycji tablicy od [3] do [rozmiar tablicy-8]
  • w niektorych pozycjach zamowienia sa tez "Nazwy rozszerzone" ktore zawsze wystepuja w nastepnej linii konkretnej pozycji zamowienia
  1. uwagi do zamowienia chyba trzeba by bylo odczytywac z przedzialow miedzy liniami zaczynajacymi sie na "Podsumowanie ilości:", "Opiekun klienta: " LUB "Informacje dodatkowe/uwagi:","Sprawdził:"

I teraz moje pytania:

  1. Czy da sie jakos usprawnic, ulatwic dostep do tych danych? Czy nie ma innej drogi niz robic to na piechote z mnostwem warunkow?
  2. Szczegolnie interesuje mnie uproszczenie wyciagania danych z pozycji zamowienia, da sie to jakos zrobic na wyrazeniach regularnych (komplet danych pozycji zamowienia jest w 2 liniach)
  3. Czy sprawdzanie tych przedzialow w ktorych spodziewac sie linii zawierajacych uwagi lub wszsytkie pozycje zamwoienia czy mozna to zrobic jakos inaczej?
0

Ja bym to w ogóle wszystko robił regexpami a nie kombinował z numerami linii albo z informacją od której pozycji stringa się coś zaczyna.
Oprócz może tych "uwag" możesz wszystko łyknąć kilkoma prostymi wyrażeniami regularnymi. Jeśli chodzi o zamówienie to też bo całe zamówienie to coś w stylu
\d+ .+? .+? \d+ \d+ \d+% \d+ \d+ .+? \d+\s+.*

0

wydaje mi się że jest duża szansa że kolumny w pozycjach są oddzielony tabulatorami
wtedy wyrażenie jest jeszcze łatwiejsze

dobrze by było jakbyś dał te pliki tu jako załączniki żeby białe znaki zostały w oryginalnej formie

0

@Varran skoro to są tabulatory to jeszcze prościej ;] A z przypisywaniem to nie bardzo rozumiem problem. Zrób w tym wyrażeniu regularnym grupy i tyle.

0

Po pierwsze analizując dokument podzieliłbym je na niezależne części.
Części te wyłapywałbym na podstawie słów kluczowych, takich jak:

  • Biuro rachunkowe
  • Magazyn:
  • Odbiorca:
  • itd
    Każdy segment przypisywałbym do innej grupy danych i łowiłbym dane wyrażeniami regularnymi.

Pytanie jednak brzmi jak bardzo sztywny jest format tego dokumentu?
Podejrzewam, że te dane to wynik przetwarzania faktury przez OCR (dlatego w jednej linii jest adres i "oryginał"), ergo zależnie od tego kto wystawia fakturę i jakiego programu używa, to ten twój wynik OCR-a będzie znacząco różny.
Jeśli mam racje to problem jest naprawdę nietuzinkowy i wymaga troszkę więcej pracy badawczej (dobrze by było też wyciągnąć więcej danych z OCR-a).

0

Ten dokument nie jest wynikiem przetwarzania OCR, plik jest generowany z programu zarzadzania magazynem (z jego odpowiednika elektronicznego, tabelki DataGridView) i jego format jest stały.

Jego zmiana jest mozliwa, ale te zmiany nie dotycza raczej zmian naglowka i stopki dokumentu, jedynie mozna dodac/odjac kolumne w pozycji pozycja zamowienia, ostatni przyklad zmian to wlasnie dodanie tej Nazwy Rozszerzonej w linii pod linia pozycji zamowienia.

na razie sprobuje go podzielic wlasnie na czesci i wyjmowac dane wyrazeniami regularnymi.

0

Właściwie rozwiązałem cały problem za pomocą klas Regex i** Match**, mam tylko problem z napisaniem właściwego testu jednego wyrażenia regularnego.

w dokumencie występuje NazwaKontrahenta i może ona przybierać takie postacie:

  1. NazwaKontrahenta Sp z o.o.
  2. NazwaFirmy, Imie NazwiskoWlasciciela
  3. "NazwaFirmy" JakiesDodatkoweDane <- z tym mam problem
  4. "Nazwa Firmy""JakiesDodatkoweDaneWCudzysłowie" <-z tym mam problem
        [Test]
        [TestCase(@"NazwaFirmy Sp. z o.o.		Zamówienie od odbiorcy ZO/\d\d\d\d\d\d/\d\d", Result = "NazwaFirmy Sp. z o.o.		Zamówienie od odbiorcy ZO/000130/13")]
        [TestCase(@"99-999 Miasto		Data i miejsce wystawienia:	20\d\d-\d\d-\d\d", Result="99-999 Miasto		Data i miejsce wystawienia:	2013-03-15")]
        [TestCase(@"	Odbiorca:								\r\n.+?\r\n", Result = @"	Odbiorca:								\r\n	""NazwaFirmy"""" Imie Nazwisko sp. j.""								\r\n")]
        public string TestRozpoznawaniaWzorcaWPliku(string wzorzec)
        {
            OdczytZO_z_PlikuCSV.OdczytajPlikCSV(@"C:\przykladowyPlik.csv");
            return OdczytZO_z_PlikuCSV.OdszukajTextWDokumencieWgWzorca(wzorzec);
        }

Nie wiem jak poprawnie zdefiniować Result w trzecim TestCase, __nie wiem jak sobie poradzić z tymi cudzysłowiami.__bo:

Przypadek 1):
jak ustawie taki:

Result = @"	Odbiorca:								\r\n	""NazwaFirmy"""" Imie Nazwisko sp. j.""								\r\n")]

to wynik testu wygląda tak:

 NUnit_Testy.OdczytZO_z_PlikuCSV_Test.TestRozpoznawaniaWzorcaWPliku("\tOdbiorca:\t\t\t\t\t\t\t\t\\r\\n.+?\\r\\n"):
  Expected string length 68 but was 64. Strings differ at index 18.
  Expected: "...ca:\t\t\t\t\t\t\t\t\\r\\n\t"NazwaFirmy"" Imie Nazwisko sp. j."\t\t\t\t\t\t\t\t\\r\\n"
  But was:  "...ca:\t\t\t\t\t\t\t\t\r\n\t"NazwaFirmy"" Imie Nazwisko sp. j."\t\t\t\t\t\t\t\t\r\n"
  ----------------------------------^

Przypadek 2):

 Result = "	Odbiorca:								\r\n	""NazwaFirmy"""" Imie Nazwisko sp. j.""								\r\n")]

to mi na etapie kompilacji podkreśla **"NazwaFirmy" **i czepia się:

Error	9	Invalid token '"NazwaFirmy"' in class, struct, or interface member declaration	(...)
Error	10	) expected	(...)

Przypadek 3):
a jeżeli Result spróbuje złożyćw ten sposób:

 Result = @"	Odbiorca:								" + Environment.NewLine + @"	""NazwaFirmy"""" Imie Nazwisko sp. j.""								" + Environment.NewLine)]

to na etapie kompilacji mam błąd ze wskazaniem na tak budowany Result, że:

Error	1	An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type	(...)
 
0

Mam problem z ułożeniem wyrażenia dla pozycji zamówienia, do podglądania efektów działania wyrażeń korzystam ze strony:
http://erik.eae.net/playground/regexp/regexp.html
i na tej stronie moje wyrazenie działa, wyłuskuje wszystie pozycje jak zaznacze po prawej RadioButton Global, ale u mnie w programie metoda OdszukajWDokumencieZbior(string wzorzecRegex) zwraca pustą kolekcję MatchCollection, mógłby ktoś coś podpowiedzieć, naprowadzić co jest nie tak z moją metodą?

Pozostałe wyrażenia do wyłuskiwania Sygnatury, NazwyOdbiorcy, DatyZałożenia wyglądają jak poniżej i działają.
(na stronie nie przyjmuje nazw grup dlatego wyrazenie dla pozycjiZamowienia nie ma na razie nazw grup)

 
        private static string wzorzecLiniiSygnaturyZamowienia = @"NazwaFirmy Sp. z o.o.\t{2}Zamówienie od odbiorcy (?<sygn>DZ/\d{4}/\d{2})";
        private static string wzorzecLiniiDatyZalozeniaDZ = @"99-999 Miasto\t{2}Data i miejsce wystawienia:\s(?<rok>20\d{2})-(?<mies>\d{2})-(?<dzien>\d{2})";
        private static string wzorzecLiniiKontrahenta = @"\sOdbiorca:\t+\r\n(?<NazwaKontrahenta>.+?)\r\n";
        private static string wzorzecLiniiPozycjiZamowienia = @"(\d+)\s(.+?)\s(.+?)\s(\d+)\s(\d+)\s(\d+%)\s(\d+)\s(\d+)\s(.+?)\s(\d+)\s(.+?)\s\r\n";
 

        private MatchCollection OdszukajWDokumencieZbior(string wzorzecRegex)
        {            
            if (!String.IsNullOrEmpty(ZawartoscOdczytanegoPliku))
            {
                return Regex.Matches(zawartoscOdczytanegoPliku, wzorzecRegex);
            }
            throw new Exception("Pusty plik, ktory mial byc przeszukiwany pod kątem wystąpinia wyrażenia regualrnego: \r\n\r\n" + wzorzecRegex);
        }

        public void UstawListePozycjiZamowienia()
        {
            MatchCollection wynikRegex = OdszukajWDokumencieZbior(wzorzecLiniiPozycjiZamowienia);
            List<PozycjaZamowienia> listaPozycji = new List<PozycjaZamowienia>();

            if (wynikRegex != null && wynikRegex.Count != 0)
            {
                for (int i = 0; i < wynikRegex.Count; i++)
                {
                    PozycjaZamowienia nowa = new PozycjaZamowienia();
                    nowa.NrPozycji = Int32.Parse(wynikRegex[i].Groups[1].Value);
                    nowa.IndexERP = wynikRegex[i].Groups[2].Value;
                    nowa.NazwaHandlowa = wynikRegex[i].Groups[3].Value;
                    nowa.Ilosc = Int32.Parse(wynikRegex[i].Groups[8].Value);
                    nowa.Jm = wynikRegex[i].Groups[9].Value;
                    nowa.NazwaSprzedazowa = wynikRegex[i].Groups[11].Value;

                    listaPozycji.Add(nowa);
                }
            }
            else
            {
                throw new Exception("Nie mozna ustawić listyPozycji zamówienia z tych wyników Match[]");
            }
        }

Pytania:
1) nie moge nigdzie znaleźć jak odwzorować w wyrażeniu regularnym znak końca linii (\r\n) np. na stronie która podałem wyżej takie oznaczenie nie działa, u mnei w programie zdaje sie że działa dla szukania NazwyKontrahenta.
2) Co jest nie tak z moim wyrazeniem dla szukania pozycji zamowienia?

EDIT:
Rozwiązaniem jest:

 private static string wzorzecLiniiPozycjiZamowienia = @"(?<Lp>\d{1,3})\t(?<Index>.{10,25})\t(?<NazwaH>.+?)\t(\d{1,5})\t(\d+?)\t(\d{2}%)\t(\d+)\t(?<Ilosc>\d+)\t(?<jm>.{1,3})\t(\d+)\s*?$\s(?<NazwaS>.*?$)"; 

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