2008-12-06 16 views
7

Estoy tratando de analizar una cadena simple en C++. Sé que la cadena contiene texto con dos puntos, seguido de inmediato por un espacio, luego un número. Me gustaría extraer solo la parte numérica de la cadena. No puedo simplemente tokenizar en el espacio (usando sstream y < <) porque el texto que está delante de los dos puntos puede contener o no espacios.¿Cómo se busca una cadena std :: para una subcadena en C++?

Algunas cadenas ejemplo podría ser:

espacio en disco total: 9852465

espacio libre en disco: 6243863

Sectores: 4095

me gustaría usar el biblioteca estándar, pero si tiene otra solución puede publicarla también, ya que a otros con la misma pregunta les gustaría ver soluciones diferentes.

Respuesta

14
std::string strInput = "Total disk space: 9852465"; 
std::string strNumber = "0"; 
size_t iIndex = strInput.rfind(": "); 
if(iIndex != std::string::npos && strInput.length() >= 2) 
{ 
    strNumber = strInput.substr(iIndex + 2, strInput.length() - iIndex - 2) 
} 
+2

¡NO use '! = -1'! Use '! = String :: npos' en su lugar. –

+1

¿Por qué no, Konrad, no funciona, es ineficiente? Las mentes inquisitivas quieren saber. – paxdiablo

+0

¡Buena captura Konrad! – BobbyShaftoe

2
const std::string pattern(": "); 
std::string s("Sectors: 4095"); 
size_t num_start = s.find(pattern) + pattern.size(); 
+0

La solución de Brian verifica los errores, la mía no: use su :) – orip

+0

Aún le daré +1 por no usar un número mágico. :) –

8

Para completar, aquí es una solución simple en C:

int value; 
if(sscanf(mystring.c_str(), "%*[^:]:%d", &value) == 1) 
    // parsing succeeded 
else 
    // parsing failed 

Explicación: el %*[^:] dice leer en tantos caracteres posibles que no son dos puntos, y el * suprime la asignación . Luego, se lee el número entero, después de los dos puntos y cualquier espacio blanco intermedio.

+0

Gracias, me gusta cuando la gente da soluciones alternativas. Estoy seguro de que esto será útil para los futuros programadores de C. –

+0

genial personalmente me gusta tu solución igual que Konrads :) aunque no busquen una subcadena, muestran cómo analizarla limpiamente –

4

No puedo tokenize en el espacio (utilizando sstream y < <) debido a que el texto delante del colon puede o no puede tener espacios en él.

derecho, pero se puede usar std::getline:

string not_number; 
int number; 
if (not (getline(cin, not_number, ':') and cin >> number)) { 
    cerr << "No number found." << endl; 
} 
+0

Eso busca una nueva línea; Supongo que tiene la intención de utilizar la sobrecarga de getline que toma un delimitador como un tercer parámetro y pasar ':' para ese parámetro? –

+0

Gracias Adam, olvidé el tercer argumento, que es realmente de lo que se trataba su publicación, como habrás adivinado. : -/ –

+0

... y otro error estúpido. Parece que ya terminé. –

3

similares a la respuesta Konrads, pero utilizando istream::ignore:

int number; 
std::streamsize max = std::numeric_limits<std::streamsize>::max(); 
if (!(std::cin.ignore(max, ':') >> number)) { 
    std::cerr << "No number found." << std::endl; 
} else { 
    std::cout << "Number found: " << number << std::endl; 
} 
+1

Sí, esa es en realidad la mejor respuesta. Sin embargo, IIRC hay algunos problemas con 'ignore' y' max' en algunas plataformas (probablemente debido a discrepancia entre firma/no firmada). Sin embargo, esta información puede estar fechada. –

+1

Sí, leí en la versión estándar que el tamaño del flujo debe tener el tipo firmado. en realidad solo miré hacia arriba, ya que me preguntaba por qué las personas no hacen streamsize (-1) :) –

3

Me sorprende que nadie ha mencionado expresiones regulares. Se agregaron como parte de TR1 y se incluyen en Boost también. Aquí está la solución usando de

typedef std::tr1::match_results<std::string::const_iterator> Results; 

std::tr1::regex re(":[[:space:]]+([[:digit:]]+)", std::tr1::regex::extended); 
std::string  str("Sectors: 4095"); 
Results   res; 

if (std::tr1::regex_search(str, res, re)) { 
    std::cout << "Number found: " << res[1] << std::endl; 
} else { 
    std::cerr << "No number found." << std::endl; 
} 

Parece mucho más trabajo, pero se obtiene más provecho de ella en mi humilde opinión de expresiones regulares.

Cuestiones relacionadas