Removing trailing newline character from fgets() input

Estoy tratando de obtener algunos datos del usuario y enviarlo a otra función en gcc. El código es algo así.

printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
    fprintf(stderr, "Error reading Name.\n");
    exit(1);
}

Sin embargo, encuentro que tiene una nueva línea \n carácter al final. Así que si entre John termina enviando John\n. ¿Cómo quito eso? \n y enviar una cuerda adecuada.

Pregunta hecha hace 13 años, 10 meses, 8 días - Por bytebarde61c


11 Respuestas:

  • Tal vez la solución más simple utiliza una de mis funciones poco conocidas favoritas, strcspn():

    buffer[strcspn(buffer, "\n")] = 0;
    

    Si usted quiere que también manejar '\r' (por ejemplo, si el flujo es binario):

    buffer[strcspn(buffer, "\r\n")] = 0; // works for LF, CR, CRLF, LFCR, ...
    

    La función cuenta el número de caracteres hasta que golpea a '\r' o a '\n' (en otras palabras, encuentra la primera '\r' o '\n'). Si no golpea nada, se detiene en el '\0' (retorno de la longitud de la cadena).

    Tenga en cuenta que esto funciona bien incluso si no hay nueva línea, porque strcspn para en una '\0'. En ese caso, toda la línea es simplemente reemplazar '\0' con '\0'.

    Respondida el Apr 22, 2010 a las 19:27 - por techmaestro

    Votos positivos: 0 | Votos negativos: 0

  • La forma elegante:

    Name[strcspn(Name, "\n")] = 0;
    

    La forma ligeramente fea:

    char *pos;
    if ((pos=strchr(Name, '\n')) != NULL)
        *pos = '\0';
    else
        /* input too long for buffer, flag error */
    

    La forma ligeramente extraña:

    strtok(Name, "\n");
    

    Note que strtok la función no funciona como se espera si el usuario entra en una cadena vacía (es decir, sólo pulsa Enter). Deja el \n carácter intacto.

    Hay otros también, por supuesto.

    Respondida el Apr 22, 2010 a las 19:35 - por codemaestro

    Votos positivos: 0 | Votos negativos: 0

  • size_t ln = strlen(name) - 1;
    if (*name && name[ln] == '\n') 
        name[ln] = '\0';
    

    Respondida el Apr 22, 2010 a las 19:44 - por techtrailblazer

    Votos positivos: 0 | Votos negativos: 0

  • A continuación se muestra un enfoque rápido para eliminar un potencial '\n' de una cuerda salvada fgets().
    Utiliza strlen(), con 2 pruebas.

    char buffer[100];
    if (fgets(buffer, sizeof buffer, stdin) != NULL) {
    
      size_t len = strlen(buffer);
      if (len > 0 && buffer[len-1] == '\n') {
        buffer[--len] = '\0';
      }
      // `len` now represents the length of the string, shortened or not.
    

    Ahora uso buffer y len según sea necesario.

    Este método tiene el beneficio secundario de un len valor para código posterior. Puede ser más rápido que strchr(Name, '\n'). Ref. YMMV, pero ambos métodos funcionan.


    buffer, desde el original fgets() no contiene "\n" en algunas circunstancias:
    A) La línea era demasiado larga para buffer tan sólo char anteriores '\n' se salva buffer. Los personajes no leídos permanecen en el arroyo.
    B) La última línea en el archivo no terminó con un '\n'.

    Si la entrada ha incorporado caracteres nulos '\0' en algún lugar, la longitud reportada por strlen() no incluirá el '\n' ubicación.


    Algunos otros problemas de respuestas:

    1. strtok(buffer, "\n"); fallas para eliminar el '\n' cuando buffer es "\n". De esto respuesta - enmendado después de esta respuesta para advertir de esta limitación.

    2. Lo siguiente falla en raras ocasiones cuando el primero char leído por fgets() es '\0'. Esto sucede cuando la entrada comienza con un embebido '\0'. Entonces... buffer[len -1] se convierte en buffer[SIZE_MAX] acceder a la memoria sin duda fuera de la gama legítima de buffer. Algo que un hacker puede probar o encontrar en tontamente leer archivos de texto UTF16. Este era el estado de un respuesta cuando esta respuesta fue escrita. Más tarde un no-OP lo editó para incluir código como el cheque de esta respuesta para "".

       size_t len = strlen(buffer);
       if (buffer[len - 1] == '\n') {  // FAILS when len == 0
         buffer[len -1] = '\0';
       }
      
    3. sprintf(buffer,"%s",buffer); es un comportamiento indefinido: Ref.. Además, no salva ningún espacio blanco líder, separador o rastreador. Ahora suprimido.

    4. [Editar debido a bueno más tarde respuesta] No hay problemas con el 1 liner buffer[strcspn(buffer, "\n")] = 0; en comparación con el rendimiento strlen() enfoque. El rendimiento en el recortado no suele ser un problema dado código está haciendo I/O - un agujero negro del tiempo de CPU. Si el siguiente código necesita la longitud de la cadena o es consciente de alto rendimiento, use esto strlen() enfoque. Else el strcspn() es una buena alternativa.

    Respondida el Apr 22, 2010 a las 19:51 - por codergeek24

    Votos positivos: 0 | Votos negativos: 0

  • Directo para eliminar el '\n' de la salida de los fgets si cada línea tiene '\n '

    line[strlen(line) - 1] = '\0';
    

    De lo contrario:

    void remove_newline_ch(char *line)
    {
        int new_line = strlen(line) -1;
        if (line[new_line] == '\n')
            line[new_line] = '\0';
    }
    

    Respondida el Apr 22, 2010 a las 20:01 - por bytebarricade

    Votos positivos: 0 | Votos negativos: 0

  • Para un solo '\n' trimming,

    void remove_new_line(char* string)
    {
        size_t length = strlen(string);
        if((length > 0) && (string[length-1] == '\n'))
        {
            string[length-1] ='\0';
        }
    }
    

    para el corte múltiple '\n',

    void remove_multi_new_line(char* string)
    {
      size_t length = strlen(string);
      while((length>0) && (string[length-1] == '\n'))
      {
          --length;
          string[length] ='\0';
      }
    }
    

    Respondida el Apr 22, 2010 a las 20:08 - por codealchemyf00f

    Votos positivos: 0 | Votos negativos: 0

  • My Newbie way ;-) Por favor avísame si es correcto. Parece estar trabajando para todos mis casos:

    #define IPT_SIZE 5
    
    int findNULL(char* arr)
    {
        for (int i = 0; i < strlen(arr); i++)
        {
            if (*(arr+i) == '\n')
            {
                return i;
            }
        }
        return 0;
    }
    
    int main()
    {
        char *input = malloc(IPT_SIZE + 1 * sizeof(char)), buff;
        int counter = 0;
    
        //prompt user for the input:
        printf("input string no longer than %i characters: ", IPT_SIZE);
        do
        {
            fgets(input, 1000, stdin);
            *(input + findNULL(input)) = '\0';
            if (strlen(input) > IPT_SIZE)
            {
                printf("error! the given string is too large. try again...\n");
                counter++;
            }
            //if the counter exceeds 3, exit the program (custom function):
            errorMsgExit(counter, 3); 
        }
        while (strlen(input) > IPT_SIZE);
    
    //rest of the program follows
    
    free(input)
    return 0;
    }
    

    Respondida el Apr 22, 2010 a las 20:13 - por scriptsculptorbf10

    Votos positivos: 0 | Votos negativos: 0

  • Los pasos para eliminar el carácter de la nueva línea de la manera quizás más obvia:

    1. Determinar la longitud de la cadena dentro NAME utilizando strlen(), cabecera string.h. Note que strlen() no cuenta la terminación \0.
    size_t sl = strlen(NAME);
    

    1. Mira si la cadena comienza con o sólo incluye uno \0 carácter ( cuerda vacía). En este caso sl lo haría 0 desde entonces strlen() como he dicho arriba no cuenta \0 y se detiene en la primera ocurrencia de ella:
    if(sl == 0)
    {
       // Skip the newline replacement process.
    }
    

    1. Compruebe si el último personaje de la cadena adecuada es un personaje de nueva línea '\n'. Si este es el caso, sustituya \n con una \0. Tenga en cuenta que los índices comienzan a 0 así que tendremos que hacerlo NAME[sl - 1]:
    if(NAME[sl - 1] == '\n')
    {
       NAME[sl - 1] = '\0';
    }
    

    Nota si sólo presiona Enter en el fgets() solicitud de cadena (el contenido de cadena sólo consistía en un carácter de nueva línea) la cadena en NAME será una cuerda vacía después.


    1. Podemos combinar el paso 2. y 3. juntos en uno solo if- afirmación utilizando el operador lógico &&:
    if(sl > 0 && NAME[sl - 1] == '\n')
    {
       NAME[sl - 1] = '\0';
    }
    

    1. El código terminado:
    size_t sl = strlen(NAME);
    if(sl > 0 && NAME[sl - 1] == '\n')
    {
       NAME[sl - 1] = '\0';
    }
    

    Si prefieres una función para usar esta técnica manejando fgets cadenas de salida en general sin refinar cada y cada vez, aquí está fgets_newline_kill:

    void fgets_newline_kill(char a[])
    {
        size_t sl = strlen(a);
    
        if(sl > 0 && a[sl - 1] == '\n')
        {
           a[sl - 1] = '\0';
        }
    }
    

    En su ejemplo proporcionado, sería:

    printf("Enter your Name: ");
    
    if (fgets(Name, sizeof Name, stdin) == NULL) {
        fprintf(stderr, "Error reading Name.\n");
        exit(1);
    }
    else {
        fgets_newline_kill(NAME);
    }
    

    Tenga en cuenta que este método no funciona si la cadena de entrada ha incrustado \0Sí. Si ese fuera el caso strlen() sólo devolvería la cantidad de caracteres hasta la primera \0. Pero esto no es un enfoque muy común, ya que las funciones de lectura de cadenas generalmente se detienen en la primera \0 y tomar la cuerda hasta ese carácter nulo.

    Aparte de la pregunta por sí misma. Trate de evitar dobles negaciones que hacen que su código no esté claro: if (!(fgets(Name, sizeof Name, stdin) != NULL) {}. Puedes simplemente hacer if (fgets(Name, sizeof Name, stdin) == NULL) {}.

    Respondida el Apr 22, 2010 a las 20:19 - por geekguru

    Votos positivos: 0 | Votos negativos: 0

  • En general, en lugar de recortar datos que no desea, evite escribirlo en primer lugar. Si no quieres la nueva línea en el búfer, no uses fgets. En lugar de eso, use getc o fgetc o scanf. Tal vez algo como:

    #include 
    #include 
    int
    main(void)
    {
            char Name[256];
            char fmt[32];
            if( snprintf(fmt, sizeof fmt, "%%%zd[^\n]", sizeof Name - 1) >= (int)sizeof fmt ){
                    fprintf(stderr, "Unable to write format\n");
                    return EXIT_FAILURE;
            }
            if( scanf(fmt, Name) == 1 ) {
                    printf("Name = %s\n", Name);
            }
            return 0;
    }
    

    Tenga en cuenta que este enfoque particular dejará sin leer la nueva línea, por lo que puede querer utilizar una cadena de formato como "%255[^\n]%*c" para descartarlo (por ejemplo, sprintf(fmt, "%%%zd[^\n]%%*c", sizeof Name - 1);), o tal vez seguir el scanf con un getchar().

    Respondida el Apr 22, 2010 a las 20:24 - por pixelpioneer

    Votos positivos: 0 | Votos negativos: 0

  • Para quitar el carácter de nueva línea (\n) al final de la cadena obtenida con fgets(), puedes hacer lo siguiente:

    • Identificar la posición del carácter de nueva línea en la cadena y reemplazarlo con un carácter nulo (`\0`), que indica el final de la cadena.
    • Puedes utilizar la función `strcspn()` de la librería string.h para encontrar la posición del carácter de nueva línea y reemplazarlo.

    Aquí te dejo un ejemplo de cómo hacerlo:

    ```c include include int main() { char Name[100]; printf("Enter your Name: "); if (!(fgets(Name, sizeof Name, stdin) != NULL)) { fprintf(stderr, "Error reading Name.\n"); return 1; }

    // Encontrar la posición del carácter de nueva línea
    size_t len = strcspn(Name, "\n");
    
    // Reemplazar el carácter de nueva línea por un carácter nulo
    if (len < sizeof(Name)) {
        Name[len] = '\0';
    } else {
    

    Respondida el Apr 23, 2010 a las 19:27 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Puedes eliminar el carácter de nueva línea \n de la cadena de entrada utilizando la función strtok() de la siguiente manera:

    c
    printf("Enter your Name: ");
    if (fgets(Name, sizeof Name, stdin) != NULL) {
        // Elimina el carácter de nueva línea al final de la cadena.
        strtok(Name, "\n");
    } else {
        fprintf(stderr, "Error reading Name.\n");
        exit(1);
    }
    

    La función strtok() toma dos argumentos: la cadena de entrada y un delimitador. El delimitador especifica los caracteres que deben utilizarse para dividir la cadena en tokens. En este caso, estamos utilizando "\n" como delimitador, lo que significa que dividirá la cadena en tokens en los saltos de línea.

    El primer argumento de strtok() es un puntero a la cadena de entrada. La función modifica la cadena de entrada eliminando el primer token (que es el nombre del usuario en este caso) y devolviendo un puntero al token.

    El segundo argumento de strtok() es el delimitador. La función busca el primer carácter delimitador en la cadena de entrada y divide la cadena en dos partes: la parte antes del delimitador (que es el nombre del usuario en este caso) y la parte después del delimitador (que es la nueva línea \n carácter).

    La función devuelve un puntero a la parte antes del delimitador. En este caso, devuelve un puntero al nombre del usuario.

    Después de llamar a strtok(), la variable Name contendrá el nombre del usuario sin el carácter de nueva línea al final.

    Respondida el Apr 23, 2010 a las 19:41 - por Gemini

    Votos positivos: 0 | Votos negativos: 0