Come posso utilizzare i delimitatori non predefiniti durante la lettura di un file di testo con std :: fstream?

Nel mio codice C ++, voglio leggere da un file di testo (* .txt) e tokenize ogni voce. Più in particolare, voglio essere in grado di leggere singole parole da un file, come “format”, “stack”, “Jason”, “europe”, ecc .

Ho scelto di usare fstream per eseguire questo compito, e non so come impostare il suo delimitatore su quelli che voglio usare (spazio, \n , come pure i trattini e persino gli apostrofi come in “Mcdonal’s”). Ho trovato spazio e \n sono i delimitatori di default, ma i trattini non lo sono, ma voglio trattarli come delimitatori in modo che quando analizzo il file, otterrò le parole in “blah blah xxx animal – cat” come semplicemente “blah” , “blah”, “xxx”, “animal”, “cat”.

Cioè, voglio essere in grado di ottenere due stringhe da “stack-overflow”, “you’re”, ecc., Ed essere ancora in grado di mantenere \n e lo spazio come delimitatori allo stesso tempo.

Un istante tratta lo “spazio bianco” come delimitatore. Usa un locale per dirgli quali caratteri sono lo spazio bianco. Una locale, a sua volta, include un faccetto di tipo ctype che classifica i tipi di carattere. Un aspetto del genere potrebbe essere qualcosa del genere:

 #include  #include  #include  #include  #include  #include  class my_ctype : public std::ctype { mask my_table[table_size]; public: my_ctype(size_t refs = 0) : std::ctype(&my_table[0], false, refs) { std::copy_n(classic_table(), table_size, my_table); my_table['-'] = (mask)space; my_table['\''] = (mask)space; } }; 

E un piccolo programma di test per dimostrarlo funziona:

 int main() { std::istringstream input("This is some input from McDonald's and Burger-King."); std::locale x(std::locale::classic(), new my_ctype); input.imbue(x); std::copy(std::istream_iterator(input), std::istream_iterator(), std::ostream_iterator(std::cout, "\n")); return 0; } 

Risultato:

 This is some input from McDonald s and Burger King. 

istream_iterator usa >> per leggere le singole stringhe dallo stream, quindi se le usi direttamente, dovresti ottenere gli stessi risultati. Le parti che devi includere sono la creazione delle impostazioni internazionali e l’utilizzo di imbue per far sì che lo stream usi quella locale.

Puoi usare

 istream::getline(char* buffer, steamsize maxchars, char delim) 

anche se questo supporta solo un singolo delimitatore. Per dividere ulteriormente le linee sui diversi delimitatori, è ansible utilizzare

 char* strtok(char* inString, const char* delims) 

che prende più delimitatori. Quando usi strtok devi solo passarlo l’indirizzo del tuo buffer la prima volta – dopo di ciò basta passare un null e ti darà il prossimo token dall’ultimo che ti ha dato, restituendo un puntatore nullo quando non ci sono Di Più.

EDIT: Un’implementazione specifica sarebbe qualcosa di simile

 char buffer[120]; //this size is dependent on what you expect the file to contain while (!myIstream.eofbit) //I may have forgotten the exact syntax of the end bit { myIstream.getline(buffer, 120); //using default delimiter of \n char* tokBuffer; tokBuffer = strtok(buffer, "'- "); while (tokBuffer != null) { cout << "token is: " << tokBuffer << "\n"; tokBuffer = strtok(null, "'- "); //I don't need to pass in the buffer again because it remembers the first time I called it } }