2010-11-16 13 views
5

Para este programa, solo he usado separadores de campo de archivos de datos en script de shell. Pero estoy tratando de usar la función de biblioteca estándar ifstream() para leer desde un archivo de datos. El único problema es que estoy recibiendo los datos al igual queC++ función ifstream y separadores de campo

A: KT5: 14: escritorio ejecutivo:

Se trata de una tabla hash, y necesito para separar los valores en la línea de la estructura de datos como así como el tipo de transacción. He estado buscando en la web y no he encontrado mucho en separadores de campo y lo que encontré fue bastante confuso.

La pregunta entonces es, ¿hay alguna manera de establecer un separador de campo con la función ifstream o existe otra función de E/S de biblioteca estándar que debería estar usando?

Gracias.

Respuesta

4

getline le da la opción de especificar un delimitador. A continuación, puede leer la entrada de una corriente como una secuencia de string separados por _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 
    ); 

Si esta es datos uniformemente estructurada que podría ser útil para definir una estructura para contenerla y aplicar operator>> para cargar cada instancia de la secuencia, usando la función anterior interna al código del operador.

Si tiene que procesar varias líneas (para que newline sea un separador de registros y un separador de campos), cargue cada línea a su vez en stringstream usando basic_istream::getline, y luego postprocesa la línea en campos como se muestra.

+1

Wow ... y no en el buen sentido. Creo que me quedaré con C. – onemasse

+0

gracias Steve !!! – rajh2504

+0

@onemasse, erm: la declaración en realidad se ve así: 'istream & getline (istream & is, string & str, char delim);', no tan malo ahora, ¿verdad? :), sin mencionar lo que 'std :: getline' te da sobre el equivalente C! :) – Nim

5

@Steve Townsend ya ha señalado una posibilidad. Si prefiere usar operator>> en lugar de std::getline, puede hacerlo también. Un istream siempre trata el espacio en blanco como un separador. Cada secuencia tiene una configuración regional asociada, y cada configuración regional incluye una faceta ctype. Esa faceta ctype es lo que usa el istream para determinar qué caracteres de entrada son espacios en blanco.

En su caso, aparentemente desea que la secuencia trate únicamente líneas nuevas y dos puntos como "espacios en blanco" (es decir, separadores), mientras que el espacio real solo se trata como un carácter "normal", no como separador.

Para hacer eso, usted puede crear una faceta ctype así:

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

Para utilizar, esto, hay que "impregnar" la corriente con una configuración regional utilizando esta faceta:

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

Soy el primero en admitir, sin embargo, que esto tiene algunas deficiencias. En primer lugar, las configuraciones regionales y las facetas generalmente están bastante poco documentadas, por lo que la mayoría de los programadores C++ de es probable que encuentren esto bastante difícil de entender (especialmente cuando todo el trabajo real ocurre "oculto", por así decirlo).

Otra posibilidad es usar Boost Tokenizer. Con toda honestidad, esto es un poco más trabajo para usar; requerirá que hagas algo así como leer una cadena y luego dividirla por separado.Al mismo tiempo, está bien documentado, es bastante conocido y se ajusta bastante mejor a las ideas preconcebidas de las personas sobre cómo hacer esas cosas, y es probable que a algunas personas les resulte más fácil seguirlo a pesar de la complejidad adicional.

+1

Estoy de acuerdo con que muchos desarrolladores de C++ no entienden bien las configuraciones regionales/facetas. Pero eso se debe a que pocas personas realmente se molestan en I18N o L10N en su código y, por lo tanto, nunca se molestan en aprender estas cosas. Pero esa es otra razón para seguir apareciendo con la mayor frecuencia posible para demostrar que, cuando se usa correctamente, hace que el código principal sea mucho más fácil de escribir y comprender. Ese es otro truco que aprendí con facetas y tengo la intención de usarlo lo antes posible. –