2010-11-16 12 views
5

Dla tego programu użyłem tylko separatorów pól z plików danych w skrypcie powłoki. Ale próbuję użyć funkcji standardowej biblioteki ifstream() do odczytu z pliku danych. Jedynym problemem jest to, że otrzymuję dane jak takc + ifstream i separatory pól

A: KT5: 14: biurkiem:

To jest dla tabeli mieszania i muszę oddzielić wartości w wierszu dla struktury danych jako oraz rodzaj transakcji. Rozglądałem się po sieci i nie znalazłem zbyt wiele na separatorach pól, a to, co odkryłem, było dość mylące.

W takim razie pytanie, czy istnieje sposób ustawienia separatora pól za pomocą funkcji ifstream lub czy należy użyć innej standardowej funkcji wejścia/wyjścia biblioteki I?

Dzięki.

Odpowiedz

4

getline daje opcję określenia ogranicznika. Następnie można odczytać wejście ze strumienia jako sekwencja string oddzielone _Delim:

template<class CharType, class Traits, class Allocator> 
    basic_istream< CharType, Traits >& getline(
     basic_istream< CharType, Traits >& _Istr, 
     basic_string< CharType, Traits, Allocator >& _Str, 
     CharType _Delim 
    ); 

Jeśli jest jednolicie zorganizowany dane mogą być przydatne do określenia struct aby je zawierać i realizować operator>> ładować każde wystąpienie z strumień, wykorzystując powyższą funkcję wewnętrzną do kodu operatora.

Jeśli musisz przetworzyć wiele linii (tak, aby nowa linia była separatorem rekordów i: separatorem pól), załaduj każdą linię z kolei do postaci stringstream, używając basic_istream::getline, a następnie przeprowadź przetwarzanie linii w pola, jak pokazano.

+1

Wow ... i nie w dobry sposób. Myślę, że będę trzymać się C. – onemasse

+0

dzięki Steve !!! – rajh2504

+0

@onemasse, erm: deklaracja faktycznie wygląda następująco: 'istream i getline (istream i is, string & str, char delim);', czy to nie takie złe? :), nie wspominając o tym, co 'std :: getline' daje ci ponad równoważny C! :) – Nim

5

@Steve Townsend już wskazał jedną możliwość. Jeśli wolisz używać operator>> zamiast std::getline, możesz to zrobić również. istream zawsze traktuje spacje jako separator. Każdy strumień ma powiązane ustawienia narodowe, a każde ustawienie narodowe obejmuje aspekt. Ten aspekt polega na tym, że istream służy do określenia, które znaki wejściowe są białymi znakami.

W twoim przypadku, najwyraźniej chcesz, aby strumień traktował tylko nowe linie i dwukropki jako "białe spacje" (tj. Separatory), podczas gdy rzeczywisty znak spacji jest traktowany jako "normalny" znak, a nie jako separator.

Aby to zrobić, można utworzyć aspekt ctype takiego:

struct field_reader: std::ctype<char> { 

    field_reader(): std::ctype<char>(get_table()) {} 

    static std::ctype_base::mask const* get_table() { 
     static std::vector<std::ctype_base::mask> 
      rc(table_size, std::ctype_base::mask()); 

     rc['\n'] = std::ctype_base::space; 
     rc[':'] = std::ctype_base::space; 
     return &rc[0]; 
    } 
}; 

użyć, to trzeba "nasycić" strumień z lokalizacji używając ten aspekt: ​​

int main() { 
    std::stringstream input("A:KT5:14:executive desk:"); 

    // have the stream use our ctype facet: 
    input.imbue(std::locale(std::locale(), new field_reader())); 

    // copy fields from the stream to standard output, one per line: 
    std::copy(std::istream_iterator<std::string>(input), 
       std::istream_iterator<std::string>(), 
       std::ostream_iterator<std::string>(std::cout, "\n")); 
    return 0; 
} 

Jestem jednak pierwszym, który przyznaje, że ma to pewne wady. Przede wszystkim lokalizacje i aspekty są generalnie słabo udokumentowane, więc większość programistów C++ prawdopodobnie uzna to za dość trudne do zrozumienia (szczególnie, gdy cała prawdziwa praca dzieje się "pod osłonami", że tak powiem).

Inną możliwością jest użycie Boost Tokenizer. Szczerze mówiąc, jest to trochę potrzebne do pracy - wymaga to odczytywania ciągu znaków, a następnie oddzielenia go oddzielnie.Jednocześnie jest dobrze udokumentowany, dość powszechnie znany i lepiej pasuje do ludzkich wyobrażeń o tym, jak robić takie rzeczy, że całkiem sporo osób prawdopodobnie będzie łatwiej je śledzić, pomimo dodatkowej złożoności.

+1

Zgadzam się, że Locale/aspekty są słabo rozumiane przez wielu programistów C++. Ale to dlatego, że niewielu ludzi rzeczywiście przeszkadza I18N lub L10N ich kodu i dlatego nigdy nie przejmuj się tym. Jest to jednak kolejny powód, aby stale go wyświetlać tak często, jak to tylko możliwe, aby pokazać, że prawidłowe użycie kodu sprawia, że ​​kod główny jest o wiele łatwiejszy do napisania i zrozumienia. To kolejna sztuczka, której nauczyłem się z aspektami i zamierzam ją wykorzystać JAK NAJSZYBCIEJ. –

Powiązane problemy