Eliminar el carácter de nueva línea al final de la entrada de fgets ()

Estoy tratando de obtener algunos datos del usuario y enviarlos a otra función en gcc. El código es algo como esto.

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

Sin embargo, me parece que tiene un carácter newline \n al final. Entonces, si ingreso a John , termina enviando a John\n . ¿Cómo elimino eso \n y envío una cadena adecuada?

La manera un poco fea:

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

La manera un poco extraña:

 strtok(Name, "\n"); 

Tenga en cuenta que la función strtok no funciona como se espera si el usuario ingresa una cadena vacía (es decir, solo presiona Enter). Deja intacto el carácter \n .

Hay otros también, por supuesto.

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

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

Si desea que también maneje '\r' (por ejemplo, si la transmisión es binaria):

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

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

Tenga en cuenta que esto funciona bien incluso si no hay línea nueva, porque strcspn detiene en '\0' . En ese caso, toda la línea simplemente está reemplazando '\0' con '\0' .

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

A continuación se muestra un enfoque rápido para eliminar un potencial '\n' de una cadena guardada por 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'; } 

Ahora usa buffer y len según sea necesario.

Este método tiene el beneficio secundario de un valor len para el 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 contendrá en "\n" bajo algunas circunstancias:
A) La línea era demasiado larga para el buffer por lo que solo el char precede a '\n' se guarda en el buffer . Los caracteres no leídos permanecen en la transmisión.
B) La última línea del archivo no finalizó con '\n' .

Si la entrada ha incrustado caracteres nulos '\0' en alguna parte, la longitud informada por strlen() no incluirá la ubicación '\n' .


Algunos otros problemas de respuestas:

  1. strtok(buffer, "\n"); no puede eliminar el '\n' cuando el buffer es "\n" . De esta respuesta – enmendada después de esta respuesta para advertir sobre esta limitación.

  2. Lo siguiente falla en raras ocasiones cuando la primera lectura de char por parte de fgets() es '\0' . Esto sucede cuando la entrada comienza con un '\0' incrustado. Luego el buffer[len -1] convierte en buffer[SIZE_MAX] accediendo a la memoria ciertamente fuera del rango legítimo de buffer . Algo que un hacker puede intentar o encontrar al leer tontamente los archivos de texto UTF16. Este fue el estado de una respuesta cuando se escribió esta respuesta. Más tarde, un OP no editado lo incluyó para incluir código como la comprobación 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 guarda espacios en blanco iniciales, separadores o finales. Ahora eliminado .

  4. [Editar debido a una buena respuesta posterior] No hay problemas con el buffer[strcspn(buffer, "\n")] = 0; 1 liner buffer[strcspn(buffer, "\n")] = 0; que no sea el rendimiento en comparación con el enfoque strlen() . El rendimiento en el recorte generalmente no es un problema dado que el código está haciendo E / S: un agujero negro de tiempo de CPU. Si el siguiente código necesita la longitud de la cadena o es altamente consciente del rendimiento, use este enfoque strlen() . De lo contrario, strcspn() es una buena alternativa.

Directo para eliminar el ‘\ n’ de la salida de los datos de las fgets si cada línea tiene ‘\ n’

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

De otra manera:

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

Para solo ‘\ n’ trmming,

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

para múltiples recortes ‘\ n’,

 void remove_new_line(char* string) { size_t length = strlen(string); while(length>0) { if(string[length-1] == '\n') { --length; string[length] ='\0'; } else break; } } 
  for(int i = 0; i < strlen(Name); i++ ) { if(Name[i] == '\n') Name[i] = '\0'; } 

Usted debe darle una oportunidad. Este código básicamente recorre la cadena hasta que encuentra el '\ n'. Cuando se encuentre, '\ n' será reemplazado por el terminador de caracteres nulo '\ 0'

Tenga en cuenta que está comparando caracteres y no cadenas en esta línea, entonces no es necesario usar strcmp ():

 if(Name[i] == '\n') Name[i] = '\0'; 

ya que usará comillas simples y no comillas dobles. Aquí hay un enlace sobre comillas simples versus dobles si desea saber más

 char name[1024]; unsigned int len; printf("Enter your name: "); fflush(stdout); if (fgets(name, sizeof(name), stdin) == NULL) { fprintf(stderr, "error reading name\n"); exit(1); } len = strlen(name); if (name[len - 1] == '\n') name[len - 1] = '\0'; 

La siguiente función es una parte de la biblioteca de procesamiento de cadenas que estoy manteniendo en Github. Elimina y caracteres no deseados de una cadena, exactamente lo que quieres

 int zstring_search_chr(const char *token,char s){ if (!token || s=='\0') return 0; for (;*token; token++) if (*token == s) return 1; return 0; } char *zstring_remove_chr(char *str,const char *bad) { char *src = str , *dst = str; while(*src) if(zstring_search_chr(bad,*src)) src++; else *dst++ = *src++; /* assign first, then incement */ *dst='\0'; return str; } 

Un ejemplo de uso podría ser

 Example Usage char s[]="this is a trial string to test the function."; char const *d=" ."; printf("%s\n",zstring_remove_chr(s,d)); Example Output thisisatrialstringtotestthefunction 

Es posible que desee comprobar otras funciones disponibles, o incluso contribuir al proyecto 🙂 https://github.com/fnoyanisi/zString

Tim Čas one liner es increíble para las cadenas obtenidas por un llamado a los fgets, porque sabes que contienen una nueva línea al final.

Si se encuentra en un contexto diferente y desea manejar cadenas que pueden contener más de una nueva línea, es posible que esté buscando strrspn. No es POSIX, lo que significa que no lo encontrará en todas las Unices. Escribí uno para mis propias necesidades.

 /* Returns the length of the segment leading to the last characters of s in accept. */ size_t strrspn (const char *s, const char *accept) { const char *ch; size_t len = strlen(s); more: if (len > 0) { for (ch = accept ; *ch != 0 ; ch++) { if (s[len - 1] == *ch) { len--; goto more; } } } return len; } 

Para aquellos que buscan un equivalente de Perl chomp en C, creo que esto es todo (chomp solo elimina la nueva línea final).

 line[strrspn(string, "\r\n")] = 0; 

La función strrcspn:

 /* Returns the length of the segment leading to the last character of reject in s. */ size_t strrcspn (const char *s, const char *reject) { const char *ch; size_t len = strlen(s); size_t origlen = len; while (len > 0) { for (ch = reject ; *ch != 0 ; ch++) { if (s[len - 1] == *ch) { return len; } } len--; } return origlen; } 

Si usa getline es una opción, sin descuidar sus problemas de seguridad y si desea apuntalar punteros, puede evitar las funciones de cadena ya que getline devuelve el número de caracteres. Algo como abajo

 #include #include int main(){ char *fname,*lname; size_t size=32,nchar; // Max size of strings and number of characters read fname=malloc(size*sizeof *fname); lname=malloc(size*sizeof *lname); if(NULL == fname || NULL == lname){ printf("Error in memory allocation."); exit(1); } printf("Enter first name "); nchar=getline(&fname,&size,stdin); if(nchar == -1){ // getline return -1 on failure to read a line. printf("Line couldn't be read.."); // This if block could be repeated for next getline too exit(1); } printf("Number of characters read :%zu\n",nchar); fname[nchar-1]='\0'; printf("Enter last name "); nchar=getline(&lname,&size,stdin); printf("Number of characters read :%zu\n",nchar); lname[nchar-1]='\0'; printf("Name entered %s %s\n",fname,lname); return 0; } 

Nota : Los [ problemas de seguridad ] con getline no deben descuidarse.

Prueba este:

  int remove_cr_lf(char *str) { int len =0; len = strlen(str); for(int i=0;i<5;i++) { if (len>0) if (str[len-1] == '\n') { str[len-1] = 0; len--; } if (len>0) if (str[len-1] == '\r') { str[len-1] = 0; len--; } } return 0; }