2012-04-29 14 views
13

En mi código C++, quiero leer un archivo de texto (* .txt) y tokenizar cada entrada. Más específicamente, quiero poder leer palabras individuales de un archivo, como "formato", "pila", "Jason", "europa", , etc..¿Cómo puedo usar delimitadores no predeterminados cuando leo un archivo de texto con std :: fstream?

yo decidimos utilizar fstream para realizar esta tarea, y no sé cómo configurar su delimitador a los que yo quiero usar (espacio, \n, así como guiones e incluso apóstrofes como en "McDonald s"). Calculé que el espacio y \n son los delimitadores por defecto, pero los guiones no, pero quiero tratarlos como delimitadores para que cuando analice el archivo, obtenga palabras en "blah blah xxx animal-cat" simplemente como "blah", "blah", "xxx", "animal", "gato".

Es decir, quiero ser capaz de obtener dos cadenas de "apilar-desbordamiento", "eres", etc, y seguir siendo capaz de mantener \n y el espacio como delimitadores al mismo tiempo.

+0

getline (secuencia, variable, delimitador); –

+0

¿Desea excluir "animal - gato" porque contiene guiones? Eso no suena como tokenizing para mí. – Johnsyweb

+0

No estoy tratando de filtrarlos; Estoy tratando de leer animales y gatos como dos palabras separadas. – FrozenLand

Respuesta

16

Un golosinas IStream "espacio en blanco" como delimitadores. Utiliza una configuración regional para indicarle qué caracteres son espacios en blanco. Una configuración regional, a su vez, incluye un tipo facet que clasifica los tipos de caracteres. una faceta de este tipo podría ser algo como esto:

#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; 
    } 
}; 

Y un pequeño programa de prueba para probar que funciona:

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; 
} 

Resultado:

This 
is 
some 
input 
from 
McDonald 
s 
and 
Burger 
King. 

istream_iterator<string> utiliza >> a leer las cadenas individuales de la transmisión, así que si los usa directamente, debería obtener los mismos resultados. Las partes que debe incluir son la creación de la configuración regional y el uso de imbue para que la transmisión use esa configuración regional.

+0

¿Está utilizando Visual Studio? Puse el código en Visual Studio (correctamente) y no compila ... – FrozenLand

+0

@ user1348863: Sí, lo probé con Visual Studio 10. –

+1

¡Excelente! N.B: [** 'std :: copy_n()' **] (http://en.cppreference.com/w/cpp/algorithm/copy_n) es un C++ 11ism. Los compiladores antiguos necesitarán 'std :: copy (classic_table(), classic_table() + table_size, my_table);' (o similar). – Johnsyweb

1

Puede utilizar

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

aunque esto sólo es compatible con un solo delimitador. Para dividir aún más las líneas en sus diferentes delimitadores, puede usar

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

que toma múltiples delimeters. Cuando usas strtok, solo necesitas pasarle la dirección de tu búfer la primera vez; después de eso simplemente pasas un nulo y te dará el siguiente token del último que te dio, devolviendo un puntero nulo cuando no haya Más.

EDIT: Una aplicación específica sería algo así como

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

¿Podría ser más específico? Digamos que quiero leer el desbordamiento de pila cuando dos palabras separadas se acumulan y se desbordan, ¿cómo hago esto? (Todavía necesito usar el espacio y \ n como delimitadores al mismo tiempo). También, como, Let's into let y s. ¡gracias! – FrozenLand

+0

La versión editada debe tokenizar en \ n, ', - y espacio. – QuantumRipple

+0

Se ve bien, pero ¿y si mi archivo es * .txt de 1 MB? ¿Qué pongo en lugar de 120? – FrozenLand

Cuestiones relacionadas