psicologicos para jugar internet huevo genios este dime asertijos acertijos acertijo c++ string stringstream

para - C++ Extraer el número desde la mitad de una cadena



dime este acertijo (8)

Tengo un vector contiene strings que siguen el formato de text_number-number

Ej .: Example_45-3

Solo quiero el primer número ( 45 en el ejemplo) y nada más que pueda hacer con mi código actual:

std::vector<std::string> imgNumStrVec; for(size_t i = 0; i < StrVec.size(); i++){ std::vector<std::string> seglist; std::stringstream ss(StrVec[i]); std::string seg, seg2; while(std::getline(ss, seg, ''_'')) seglist.push_back(seg); std::stringstream ss2(seglist[1]); std::getline(ss2, seg2, ''-''); imgNumStrVec.push_back(seg2); }

¿Hay formas más simples y simplificadas de hacer esto? Y si es así, ¿qué son?

Pido por puro deseo de aprender a codificar mejor, ya que al final del día, el código anterior solo extrae con éxito el primer número, pero parece largo y completo.


actualizado para C ++ 11 2018-12-04

Intenté actualizar esta respuesta para usar C ++ 11 en mi máquina, pero fallé porque mi compilador g ++ no tiene soporte completo <regex> ... así que seguí recibiendo el code=4 std::regex_error code=4 (es decir, "falta el corchete" ) excepciones para cualquier expresión regular con clases de caracteres de corchete std::regex("[0-9]") .

Aparentemente, se implementó y lanzó el soporte completo para C ++ 11 <regex> para g ++ versión 4.9.x y el 26 de junio de 2015 . Sugerencia de sombrero para SO preguntas #1 y #2 para averiguar la versión del compilador que necesita ser 4.9.x.

Aquí está el código de C ++ 11 que debería funcionar pero no pude probarlo:

#include <iostream> #include <string> #include <regex> using std::cout; using std::endl; int main() { std::string input = "Example_45-3"; std::string output = std::regex_replace( input, std::regex("[^0-9]*([0-9]+).*"), std::string("//1") ); cout << input << endl; cout << output << endl; }

Solución de impulso que solo requiere C ++ 98.

Ejemplo de implementación mínima que funciona en muchas cadenas (no solo cadenas de la forma "texto_45-texto":

#include <iostream> #include <string> using namespace std; #include <boost/regex.hpp> int main() { string input = "Example_45-3"; string output = boost::regex_replace( input, boost::regex("[^0-9]*([0-9]+).*"), string("//1") ); cout << input << endl; cout << output << endl; }

salida de consola:

Example_45-3 45

Otras cadenas de ejemplo en las que esto funcionaría:

  • "asdfasdf 45 sdfsdf"
  • "X = 45, sdfsdf"

Para este ejemplo usé g ++ en Linux con #include <boost/regex.hpp> y -lboost_regex . También puedes usar C ++ 11x regex.

Siéntase libre de editar mi solución si tiene un regex mejor.

Comentario:

Si no hay restricciones de rendimiento, usar Regex es ideal para este tipo de cosas porque no estás reinventando la rueda (al escribir un montón de código de análisis de cadena que toma tiempo para escribir / probar completamente).

Además, si / cuando sus cadenas se vuelven más complejas o tienen patrones más variados, las expresiones regulares se adaptan fácilmente a la complejidad. (El patrón de ejemplo de la pregunta es bastante fácil. Pero a menudo, un patrón más complejo tomaría 10-100 líneas de código cuando una expresión regular de una línea haría lo mismo).


Esto debería ser más eficiente que la solución de Ashot Khachatryan. Tenga en cuenta el uso de ''_'' y ''-'' lugar de "_" y "-" . Y también, la posición inicial de la búsqueda de ''-'' .

inline std::string mid_num_str(const std::string& s) { std::string::size_type p = s.find(''_''); std::string::size_type pp = s.find(''-'', p + 2); return s.substr(p + 1, pp - p - 1); }

Si necesita un número en lugar de una cadena, como lo que ha hecho la solución de Alexandr Lapenkov, también puede intentar lo siguiente:

inline long mid_num(const std::string& s) { return std::strtol(&s[s.find(''_'') + 1], nullptr, 10); }


La "mejor" forma de hacer esto en C ++ 11 y versiones posteriores es probablemente usando expresiones regulares , que combinan alta expresividad y alto rendimiento cuando la prueba se repite con la suficiente frecuencia.

El siguiente código muestra los conceptos básicos. Debe #include <regex> para que funcione.

// The example inputs std::vector<std::string> inputs { "Example_0-0", "Example_0-1", "Example_0-2", "Example_0-3", "Example_0-4", "Example_1-0", "Example_1-1", "Example_1-2", "Example_1-3", "Example_1-4" }; // The regular expression. A lot of the cost is incurred when building the // std::regex object, but when it''s reused a lot that cost is amortised. std::regex imgNumRegex { "^[^_]+_([[:digit:]]+)-([[:digit:]]+)$" }; for (const auto &input: inputs){ // This wil contain the match results. Parts of the regular expression // enclosed in parentheses will be stored here, so in this case: both numbers std::smatch matchResults; if (!std::regex_match(input, matchResults, imgNumRegex)) { // Handle failure to match abort(); } // Note that the first match is in str(1). str(0) contains the whole string std::string theFirstNumber = matchResults.str(1); std::string theSecondNumber = matchResults.str(2); std::cout << "The input had numbers " << theFirstNumber; std::cout << " and " << theSecondNumber << std::endl; }


Mira esto

std::string ex = "Example_45-3"; int num; sscanf( ex.c_str(), "%*[^_]_%d", &num );


Puedo pensar en dos maneras de hacerlo:

  • Usar expresiones regulares
  • Use un iterador para recorrer la cadena y copie cada dígito consecutivo en un búfer temporal. Rompe cuando alcanza una longitud irrazonable o en el primer no dígito después de una cadena de dígitos consecutivos. Entonces tienes una cadena de dígitos que puedes convertir fácilmente.

También puedes usar el find_first_of y find_first_not_of para encontrar la primera "serie de números" en cualquier cadena.

std::string first_numberstring(std::string const & str) { std::size_t const n = str.find_first_of("0123456789"); if (n != std::string::npos) { std::size_t const m = str.find_first_not_of("0123456789", n); return str.substr(n, m != std::string::npos ? m-n : m); } return std::string(); }


Usando la respuesta de @ Pixelchemist y por ejemplo, std::stoul :

bool getFirstNumber(std::string const & a_str, unsigned long & a_outVal) { auto pos = a_str.find_first_of("0123456789"); try { if (std::string::npos != pos) { a_outVal = std::stoul(a_str.substr(pos)); return true; } } catch (...) { // handle conversion failure // ... } return false; }


std::string s = "Example_45-3"; int p1 = s.find("_"); int p2 = s.find("-"); std::string number = s.substr(p1 + 1, p2 - p1 - 1)