2012-04-29 11 views
13

Nel mio codice C++, voglio leggere da un file di testo (* .txt) e tokenize ogni voce. Nello specifico, voglio essere in grado di leggere singole parole da un file, come "format", "stack", "Jason", "europe", ecc..Come posso utilizzare i delimitatori non predefiniti durante la lettura di un file di testo con std :: fstream?

ho scelto di usare fstream per svolgere questo compito, e non so come impostare è delimitatore a quelle che voglio usare (spazio, \n, così come i trattini e anche apostrofi come in "McDonal di"). Ho immaginato lo spazio e \n sono i delimitatori predefiniti, 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", "sei", ecc, ed essere ancora in grado di mantenere \n e lo spazio come delimitatori allo stesso tempo.

+0

getline (flusso, variabile, delimitatore); –

+0

Vuoi filtrare "animale - gatto" perché contiene trattini? Questo non mi sembra un rammendo. – Johnsyweb

+0

Non sto cercando di filtrarli; Sto cercando di leggere animali e gatti come due parole separate. – FrozenLand

risposta

16

un istream ossequi "spazio bianco" come delimitatori. Usa un locale per dirgli quali caratteri sono lo spazio bianco. Una locale, a sua volta, include un tipo di telefono facet che classifica i tipi di carattere. Tale aspetto potrebbe essere simile a questa:

#include <locale> 
#include <iostream> 
#include <algorithm> 
#include <iterator> 
#include <vector> 
#include <sstream> 

class my_ctype : public 
std::ctype<char> 
{ 
    mask my_table[table_size]; 
public: 
    my_ctype(size_t refs = 0) 
     : std::ctype<char>(&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 dimostrare che 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<std::string>(input), 
     std::istream_iterator<std::string>(), 
     std::ostream_iterator<std::string>(std::cout, "\n")); 

    return 0; 
} 

Risultato:

This 
is 
some 
input 
from 
McDonald 
s 
and 
Burger 
King. 

istream_iterator<string> utilizza >> di leggere le singole stringhe dal flusso, quindi se li usi direttamente, dovresti ottenere gli stessi risultati. Le parti che devi includere sono la creazione delle impostazioni internazionali e l'uso di imbue per far sì che lo streaming usi quella locale.

+0

Quindi stai usando lo studio visivo? Inserisco il codice in Visual Studio (correttamente) e non compila ... – FrozenLand

+0

@ user1348863: Sì, l'ho provato con Visual Studio 10. –

+1

Eccellente! N.B: [** 'std :: copy_n()' **] (http://en.cppreference.com/w/cpp/algorithm/copy_n) è un C++ 11ism. I compilatori più vecchi avranno bisogno di 'std :: copy (classic_table(), classic_table() + table_size, my_table);' (o simile). – Johnsyweb

1

È possibile utilizzare

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

anche se questa supporta solo un singolo delimitatore. Per dividere ulteriormente le righe sui diversi delimitatori, è possibile utilizzare

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

che richiede 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 
    } 
} 
+0

Quindi potresti essere più specifico? Diciamo che voglio leggere lo stack overflow mentre due parole separate si accatastano e si sovrappongono, come posso fare? (Ho ancora bisogno di usare lo spazio e \ n come delimitatori allo stesso tempo.) Inoltre, come, Let's into let and s. grazie! – FrozenLand

+0

La versione modificata dovrebbe tokenize su \ n, ', -, e spazio. – QuantumRipple

+0

Sembra buono, ma cosa succede se il mio file è * .txt di 1 MB? cosa metto al posto di 120? – FrozenLand

Problemi correlati