La lectura de ifstream no leerá el espacio en blanco

Estoy implementando un lexer personalizado en C ++ y cuando bash leer en espacios en blanco, el ifstream no lo leerá. Estoy leyendo carácter por carácter usando >> , y todo el espacio en blanco se ha ido. ¿Hay alguna manera de hacer que el ifstream mantenga todos los espacios en blanco y leerlo? Sé que al leer cadenas enteras, la lectura se detendrá en el espacio en blanco, pero esperaba que leyendo carácter por personaje, evitaría este comportamiento.

Intento: .get() , recomendado por muchas respuestas, pero tiene el mismo efecto que std::noskipws , es decir, obtengo todos los espacios ahora, pero no el carácter de nueva línea que necesito para leer algunos constructos.

Aquí está el código ofensivo (comentarios extendidos truncados)

 while(input >> current) { always_next_struct val = always_next_struct(next); if (current == L' ' || current == L'\n' || current == L'\t' || current == L'\r') { continue; } if (current == L'/') { input >> current; if (current == L'/') { // explicitly empty while loop while(input.get(current) && current != L'\n'); continue; } 

Estoy rompiendo la línea horizontal y mirando cada valor de la current cuando entra, y \r o \n definitivamente no están entre ellos- la entrada simplemente salta a la siguiente línea en el archivo de entrada.

Hay un manipulador para deshabilitar el comportamiento de omisión de espacio en blanco:

 stream >> std::noskipws; 

El operador >> come espacio en blanco (espacio, pestaña, nueva línea). Usa yourstream.get() para leer cada personaje.

Editar:

Cuidado: las plataformas (Windows, Un * x, Mac) difieren en la encoding de nueva línea. Puede ser ‘\ n’, ‘\ r’ o ambos. También depende de cómo se abre la secuencia de archivos (texto o binario).

Editar (analizar código):

Después

  while(input.get(current) && current != L'\n'); continue; 

habrá \n en el archivo current , si no se llega al final del archivo. Después de eso continúas con el bucle outmost. Allí, el primer personaje de la línea siguiente se lee en la current . ¿No es eso lo que querías?

Traté de reproducir tu problema (usando char y cin lugar de wchar_t y wifstream ):

 //: get.cpp : compile, then run: get < get.cpp #include  int main() { char c; while (std::cin.get(c)) { if (c == '/') { char last = c; if (std::cin.get(c) && c == '/') { // std::cout < < "Read to EOL\n"; while(std::cin.get(c) && c != '\n'); // this comment will be skipped // std::cout << "go to next line\n"; std::cin.putback(c); continue; } else { std::cin.putback(c); c = last; } } std::cout << c; } return 0; } 

Este progtwig, aplicado a sí mismo, elimina todos los comentarios de líneas C ++ en su salida. El ciclo while interno no consume todo el texto hasta el final del archivo. Tenga en cuenta la putback(c) . Sin eso, la nueva línea no aparecería.

Si no funciona igual para wifstream , sería muy extraño, excepto por una razón: cuando el archivo de texto abierto no se guarda como char de 16 bits y el \n char termina en el byte incorrecto ...

Ajustar la secuencia (o su búfer, específicamente) en un std::streambuf_iterator ? Eso debería ignorar todo el formato, y también darle una buena interfaz de iterador.

Alternativamente, un enfoque mucho más eficiente y a prueba de tontos podría simplemente usar la API de Win32 (o Boost) para mapear la memoria del archivo. Luego puede recorrerlo usando punteros simples, y tiene la garantía de que el tiempo de ejecución no saltará ni convertirá nada.

Los extractores de flujo se comportan igual y omiten espacios en blanco.

Si desea leer cada byte, puede usar las funciones de entrada sin formato, como stream.get(c) .

¿Por qué no simplemente usar getline ?

Obtendrá todos los espacios en blanco, y aunque no obtendrá los caracteres de fin de línea, sabrá dónde mienten 🙂

Puede abrir la secuencia en modo binario:

 std::wifstream stream(filename, std::ios::binary); 

Perderá todas las operaciones de formateo que proporcione mi transmisión si lo hace.

La otra opción es leer todo el flujo en una cadena y luego procesar la cadena:

 std::wostringstream ss; ss < < filestream.rdbuf(); 

Por supuesto, obtener la secuencia del ostringstream requiere una copia adicional de la cadena, por lo que podría considerar cambiar esto en algún momento para usar una transmisión personalizada si se siente aventurero. EDITAR: alguien más menciona istreambuf_iterator, que es probablemente una mejor manera de hacerlo que leer todo el flujo en una cadena.

Simplemente puede ajustar la secuencia en std :: streambuf_iterator para obtener datos con todos los espacios en blanco y nuevas líneas como esta.

  /*Open the stream in default mode.*/ std::ifstream myfile("myfile.txt"); if(myfile.good()) { /*Read data using streambuffer iterators.*/ vector buf((std::istreambuf_iterator(myfile)), (std::istreambuf_iterator())); /*str_buf holds all the data including whitespaces and newline .*/ string str_buf(buf.begin(),buf.end()); myfile.close(); } 

Terminé simplemente abriendo la API de Windows y usándola para leer todo el archivo en un buffer primero, y luego leer ese buffer carácter por carácter. Gracias chicos.