2010-03-29 10 views
11

Co jest najlepszym rozwiązaniem, jeśli chcę, aby podczas czytania pliku z separatorem średnik „upgrade” starego C-kod do nowszych C++Jaki jest nowoczesny styl równoważny (C++) dla starszej (C-podobnej) metody fscanf?

/* reading in from file C-like: */ 
fscanf(tFile, "%d", &mypost.nr); /*delimiter ; */ 
fscanf(tFile, " ;%[^;];", mypost.aftername);/* delimiter ; */ 
fscanf(tFile, " %[^;]", mypost.forename); /*delimiter ; */ 
fscanf(tFile, " ;%[^;];", mypost.dept);/*delimiter ; */ 
fscanf(tFile, " %[^;];", mypost.position);/* delimiter ; */ 
fscanf(tFile, "%d", &mypost.nr2); 

//eqivalent best C++ method achieving the same thing? 
+0

Zastanawiam się, jak ścisłe jest fscanf? Jeśli czytasz wszystkie znaki aż do średnika w wierszu z imieniem, w jaki sposób następna linia może odczytać spację przed średnikiem? - Ponadto, 'fscanf' prawdopodobnie nie byłby taki zły, gdybyś mógł również określić maksymalną liczbę znaków do odczytania gdzieś. – UncleBens

Odpowiedz

11

Można przeciążenia operatora prawy shift na istream dla struktury tak:

std::istream& operator>>(std::istream& is, mypost_struct& mps) { 
    is >> mps.nr; 
    is.ignore(1, ';'); 
    is.getline(mps.forename, 255, ';'); 
    is.getline(mps.aftername, 255, ';'); 
    is >> mps.dept; 
    is.ignore(1, ';'); 
    is >> mps.position; 
    is.ignore(1, ';'); 
    is >> mps.nr2; 

    return is; 
} 

Następnie, wejście jest tak proste, jak is >> mypost;, gdzie is jest plikiem, który został otwarty.

Edit: @UncleBens Dzięki za wskazanie tego, że zapomniał wziąć przestrzenie w rachunku. Zaktualizowałem odpowiedź, zakładając, że imię i nazwisko prawdopodobnie zawierają spacje. I było to dość kłopotliwe nieco o ograniczniki jest dwukrotnie cytowany ...

Właśnie sprawdziłem go stosując definicję struct jak poniżej:

struct mypost_struct { 
    int nr; 
    char forename[255], aftername[255]; 
    int dept, position, nr2; 
}; 

.. i wynik był jak oczekiwano.

+0

Zastanawiam się, po co są wszystkie upusty. Pomysł zapewnienia przeciążenia '>>' jest w porządku, ale implementacja (** jak ** odczytać rozdzielone dane wejściowe) jest kompletnie zepsuta. "ignore" nie ma tego formularza, a nawet jeśli go naprawisz, nie zmieni to działania 'istream.operator >>' i użyje ";" jako ogranicznik. To działałoby, jeśli dane wejściowe są również oddzielone białymi znakami i żaden z ciągów nie zawiera więcej niż jednego słowa. – UncleBens

+0

Dzięki za wskazanie tego :) – susmits

3

Jak @susmits mówi, ale można też użyć zwrócony strumień jako warunkowy, jak:

if (is >> mps.nr && is.ignore(1, ";") && is >> mps.aftername && ...) { 
    // all is well ... 
} else { 
    // bad input format 
} 

lub nawet:

if (is >> mps.nr >> ignore(";") >> mps.aftername >> ...) { 
    // all is well ... 
} else { 
    // bad input format 
} 
1

Co jest najlepszym rozwiązaniem, jeśli chcę do "uaktualnić" stary kod C do nowszego C++ ...?

IMHO, najlepszym sposobem na zrobienie tego będzie odczytanie pliku wiersz po wierszu i użycie regular expressions for parsing.