tipos regulares numeros letras imprimir expresiones entrada ejemplos datos convertir caracteres busqueda c++ stringstream

c++ - regulares - input python



Cómo probar si el operador de cadena de caracteres>> ha analizado un tipo incorrecto y omitirlo (5)

El siguiente código funciona bien para omitir la palabra incorrecta y recopilar los valores double válidos

istringstream iss("2.832 1.3067 nana 1.678"); double num = 0; while(iss >> num || !iss.eof()) { if(iss.fail()) { iss.clear(); string dummy; iss >> dummy; continue; } cout << num << endl; }

Aquí hay una muestra completamente funcional .

Su muestra casi lo hizo bien, solo faltaba consumir el campo de entrada no válido de la transmisión después de detectar que estaba en un formato incorrecto

if (parser.fail()) { std::cout << "Failed!" << std::endl; parser.clear(); string dummy; parser >> dummy; }

En su caso, la extracción intentará leer de nuevo desde "nana" en la última iteración, de ahí las dos últimas líneas en la salida.

También tenga en cuenta el truco sobre iostream::fail() y cómo probar realmente para iostream::eof() en mi primera muestra. Existe una conocida pregunta y respuesta , por la cual las pruebas simples de EOF como una condición de bucle se consideran erróneas. Y responde bien, cómo romper el bucle de entrada cuando se encontraron valores inesperados / inválidos. Pero la forma de omitir / ignorar los campos de entrada no válidos no se explica allí (y no se solicitó).

Estoy interesado en discutir métodos para usar stringstream para analizar una línea con múltiples tipos. Yo comenzaría mirando la siguiente línea:

"2.832 1.3067 nana 1.678"

Ahora supongamos que tengo una línea larga que tiene múltiples strings y doubles . La forma obvia de resolver esto es convertir la cadena en un token y luego verificar la conversión de cada uno. Estoy interesado en omitir este segundo paso y usar stringstream directamente para encontrar solo los números.

Pensé que una buena forma de abordar esto sería leer a través de la cadena y comprobar si se ha establecido el failbit , que será si trato de analizar una cadena en un doble.

Digamos que tengo el siguiente código:

string a("2.832 1.3067 nana 1.678"); stringstream parser; parser.str(a); for (int i = 0; i < 4; ++i) { double b; parser >> b; if (parser.fail()) { std::cout << "Failed!" << std::endl; parser.clear(); } std::cout << b << std::endl; }

Imprimirá lo siguiente:

2.832 1.3067 Failed! 0 Failed! 0

No me sorprende que no pueda analizar una cadena, pero ¿qué está sucediendo internamente de manera que no puede borrar su failbit y analizar el siguiente número?


He creado una versión más afinada para esto, que es capaz de omitir caracteres de entrada no válidos (sin necesidad de separar números double con caracteres en blanco):

#include <iostream> #include <sstream> #include <string> using namespace std; int main() { istringstream iss("2.832 1.3067 nana1.678 xxx.05 meh.ugh"); double num = 0; while(iss >> num || !iss.eof()) { if(iss.fail()) { iss.clear(); while(iss) { char dummy = iss.peek(); if(std::isdigit(dummy) || dummy == ''.'') { // Stop consuming invalid double characters break; } else { iss >> dummy; // Consume invalid double characters } } continue; } cout << num << endl; } return 0; }

Salida

2.832 1.3067 1.678 0.05

Demo en vivo


Pocas diferencias menores a la respuesta de πάντα ῥεῖ - hace que también maneje, por ejemplo, representaciones numéricas negativas, etc., además de ser, en mi humilde opinión, un poco más simple de leer.

#include <iostream> #include <sstream> #include <string> int main() { std::istringstream iss("2.832 1.3067 nana1.678 x-1E2 xxx.05 meh.ugh"); double num = 0; for (; iss; ) if (iss >> num) std::cout << num << ''/n''; else if (!iss.eof()) { iss.clear(); iss.ignore(1); } }

Salida:

2.832 1.3067 1.678 -100 0.05

(verlo corriendo here )


Puede usar std::istringstream::eof() para validar una entrada como esta:

#include <string> #include <sstream> #include <iostream> // remove white-space from each end of a std::string inline std::string& trim(std::string& s, const char* t = " /t") { s.erase(s.find_last_not_of(t) + 1); s.erase(0, s.find_first_not_of(t)); return s; } // serial input std::istringstream in1(R"~( 2.34 3 3.f 3.d .75 0 wibble )~"); // line input std::istringstream in2(R"~( 2.34 3 3.f 3.d .75 0 wibble )~"); int main() { std::string input; // NOTE: This technique will not work if input is empty // or contains only white-space characters. Therefore // it is safe to use after a conditional extraction // operation >> but it is not reliable after std::getline() // without further checks. while(in1 >> input) { // input will not be empty and will not contain white-space. double d; if((std::istringstream(input) >> d >> std::ws).eof()) { // d is a valid double std::cout << "d1: " << d << ''/n''; } } std::cout << ''/n''; while(std::getline(in2, input)) { // eliminate blank lines and lines // containing only white-space (trim()) if(trim(input).empty()) continue; // NOW this is safe to use double d; if((std::istringstream(input) >> d >> std::ws).eof()) { // d is a valid double std::cout << "d2: " << d << ''/n''; } } }

Esto funciona porque la comprobación de eof() garantiza que solo se ingresó el doble y no como 12d4 .


Si le gusta la concisión, esta es otra opción que (ab?) Usa && para completar solo cuando un número ha sido analizado exitosamente, y cuando un número no es analizado usa el operador de coma para poder clear() estado de error de transmisión dentro del condicional antes de leer un personaje que se ignorará ...

#include <iostream> #include <sstream> #include <string> int main() { std::istringstream iss("2.832 1.3067 nana1.678 x-1E2 xxx.05 meh.ugh"); double num = 0; char ignored; while (iss >> num && std::cout << num << ''/n'' || (iss.clear(), iss) >> ignored) ; }

http://ideone.com/WvtvfU