¿Cómo puedo extraer un número entero dentro de una cadena?

8

Estoy trabajando en una tarea y como parte de ella necesito extraer el entero de una cadena.

Intenté usar la atoi()función, pero siempre devuelve a 0, así que cambié a strtol(), pero aún devuelve a 0.

El objetivo es extraer los enteros de la cadena y pasarlos como argumentos a una función diferente. Estoy usando una función que luego usa estos valores para actualizar algunos datos ( update_stats).

Tenga en cuenta que soy bastante nuevo en la programación en lenguaje C, pero este fue mi intento:

void get_number (char str[]) {
    char *end;
    int num;
    num = strtol(str, &end, 10);
    update_stats(num);
    num = strtol(end, &end, 10);
    update_stats(num);
}

El propósito de esto es en una cadena "e5 d8"(por ejemplo) extraería el 5y el 8de esa cadena.

El formato de la cadena es siempre el mismo.

¿Cómo puedo hacer esto?

Ramux05
fuente
1
No hay un error obvio en esta parte del código, por lo que el problema no puede reproducirse.
Lundin
1
Puede usar bucles para omitir todos los caracteres que no sean dígitos isdigitantes de usarstrtol
Bodo
1
Ambos atoiy strtolespere recibir el puntero al primer carácter de un número: su puntero ya debe estar apuntando a un dígito. Ni "e" ni "d" son dígitos cuando la base es 10. Para encontrar los números en la cadena, debe escribir un código para examinar cada carácter y determinar si es un dígito o no. Una vez que haya encontrado un dígito, puede convertirlo (solo un dígito) o la secuencia de dígitos (varios dígitos) a un número, dependiendo de cuál sea su necesidad.
Eric Postpischil
@Lundin: Hay un error perfectamente obvio; pasar un puntero al primer carácter de "e5 d8"to strtolno es una forma correcta de encontrar el "5" y convertirlo en un número.
Eric Postpischil
@EricPostpischil De hecho, si esa es la entrada real. Difícil de decir sin el código de llamada.
Lundin

Respuestas:

7

strtolno encuentra un número en una cadena. Convierte el número al comienzo de la cadena . (Omite espacios en blanco, pero nada más).

Si necesita encontrar dónde comienza un número, puede usar algo como:

const char* nump = strpbrk(str, "0123456789");
if (nump == NULL) /* No number, handle error*/

( man strpbrk)

Si sus números pueden estar firmados, necesitará algo un poco más sofisticado. Una forma es hacer lo anterior y luego hacer una copia de seguridad de un personaje si el personaje anterior es -. Pero cuidado con el comienzo de la cadena:

if ( nump != str && nump[-1] == '-') --nump;

Simplemente poner -en el strpbrkargumento produciría coincidencias falsas en entradas como non-numeric7.

rici
fuente
2

Si el formato es siempre así, esto también podría funcionar

#include <stdio.h>

int main()
{
    char *str[] = {"a5 d8", "fe55 eec2", "a5 abc111"};
    int num1, num2;

    for (int i = 0; i < 3; i++) {
      sscanf(str[i], "%*[^0-9]%d%*[^0-9]%d", &num1, &num2);
      printf("num1: %d, num2: %d\n", num1, num2);
    }
    return 0;
}

Salida

num1: 5, num2: 8                                                                                                                                                                   
num1: 55, num2: 2                                                                                                                                                                  
num1: 5, num2: 111

%[^0-9]coincidirá con cualquier carácter que no sea un dígito. Al agregar lo *mismo, esto %*[^0-9]indica que los datos deben leerse de la cadena, pero se ignoran.

Eraklon
fuente
Buen uso de sscanf. Realmente aprecio el esfuerzo. Sin embargo, en ninguna parte se especifica que el formato es la forma en que ha dado por sentado. Intenta agregar un poco más de genérico si puedes. Además, si el usuario está atascado en E / S y conversión de cadena a entero, existe una alta probabilidad de que él / ella sea nuevo. Por lo tanto, sería realmente útil agregar o al menos proporcionar un enlace a la documentación, por ejemplo, en este caso sscanf,. Buena respuesta aunque :)
d4rk4ng31
1
Bien gracias. Pero también tenga en cuenta que la pregunta dice "El formato de la cadena es siempre el mismo", lo que implica que podría ser el mismo. La genérica es algo bueno, pero la ausencia de ella permite que la solución funcione así. El primer éxito en google para sscanfes la documentación. Creo que lo que realmente puede mejorar aquí es una pequeña explicación del formato, que puedo agregar aquí.
Eraklon
Sí cierto. Lo siento. Supongo que me perdí la última declaración. Buena respuesta :)
d4rk4ng31
2

Te sugiero que escribas la lógica por tu cuenta. Lo sé, es como reinventar la rueda , pero en ese caso, tendrás una idea de cómo funciona realmente la biblioteca.

Aquí hay una función que propongo:

bool getNumber(str,num_ptr)
char* str;
long* num_ptr;
{
    bool flag = false;
    int i = 0;
    *num_ptr = 0;
    char ch = ' ';
    while (ch != '\0') {
        ch = *(str + i);
        if (ch >= '0' && ch <= '9') {
            *num_ptr = (*num_ptr) * 10 + (long)(ch - 48);
             flag = true;
        }
        i++;
    }
    return flag;
}

No olvides pasar una cuerda con un \0 al final :)

d4rk4ng31
fuente
Esta función escanea toda la cadena y devuelve un número que consta de los dígitos en orden.
d4rk4ng31
teniendo en cuenta c, es posible convertir a bool int e truey falsea 1y 0respectivamente
d4rk4ng31