Removendo o caractere de nova linha à direita da input fgets ()

Eu estou tentando obter alguns dados do usuário e enviá-lo para outra function no gcc. O código é algo assim.

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

No entanto, acho que tem um caractere de nova linha \n no final. Então, se eu digitar John ele acaba enviando John\n . Como removo \n e envio uma string apropriada.

A maneira um pouco feia:

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

A maneira um pouco estranha:

 strtok(Name, "\n"); 

Observe que a function strtok não funciona como esperado se o usuário inserir uma string vazia (isto é, pressionar apenas Enter). Deixa o caractere \n intacto.

Há outros também, claro.

Talvez a solução mais simples use uma das minhas funções pouco conhecidas favoritas, strcspn() :

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

Se você quer que ele também manipule '\r' (digamos, se o stream é binário):

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

A function conta o número de caracteres até atingir um '\r' ou um '\n' (em outras palavras, ele encontra o primeiro '\r' ou '\n' ). Se não acertar nada, ele pára no '\0' (retornando o comprimento da string).

Observe que isso funciona bem, mesmo que não haja nova linha, porque o strcspn pára em '\0' . Nesse caso, a linha inteira está simplesmente substituindo '\0' por '\0' .

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

Abaixo está uma abordagem rápida para remover um possível '\n' de uma string salva por fgets() .
Ele usa strlen() , com 2 testes.

 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'; } 

Agora use buffer e len conforme necessário.

Esse método tem o benefício colateral de um valor len para código subseqüente. Pode ser facilmente mais rápido que o strchr(Name, '\n') . Ref YMMV, mas ambos os methods funcionam.


buffer , a partir do fgets() original fgets() não irá conter em "\n" sob algumas circunstâncias:
A) A linha era muito longa para o buffer portanto somente o char precedendo o '\n' é salvo no buffer . Os caracteres não lidos permanecem no stream.
B) A última linha no arquivo não terminou com um '\n' .

Se a input incluiu caracteres nulos '\0' em algum lugar, o tamanho relatado por strlen() não includeá o local '\n' .


Alguns outros problemas de resposta:

  1. strtok(buffer, "\n"); falha ao remover o '\n' quando o buffer é "\n" . A partir desta resposta – alterada após esta resposta para avisar desta limitação.

  2. O seguinte falha em raras ocasiões quando o primeiro char lido por fgets() é '\0' . Isso acontece quando a input começa com um '\0' incorporado. Então o buffer[len -1] se torna buffer[SIZE_MAX] acessando a memory certamente fora do intervalo legítimo de buffer . Algo que um hacker pode tentar ou encontrar lendo arquivos de texto UTF16 insensatamente. Este foi o estado de uma resposta quando esta resposta foi escrita. Mais tarde, um não OP o editou para include código como a verificação desta resposta para "" .

     size_t len = strlen(buffer); if (buffer[len - 1] == '\n') { // FAILS when len == 0 buffer[len -1] = '\0'; } 
  3. sprintf(buffer,"%s",buffer); é um comportamento indefinido: ref . Além disso, ele não salva espaços em branco iniciais, separados ou à direita. Agora excluído .

  4. [Editar devido a boa resposta posterior] Não há problemas com o buffer[strcspn(buffer, "\n")] = 0; 1 liner buffer[strcspn(buffer, "\n")] = 0; diferente de desempenho em comparação com a abordagem strlen() . O desempenho no corte geralmente não é um problema dado ao código estar fazendo I / O – um buraco negro de tempo de CPU. Se o código a seguir precisar do tamanho da string ou for altamente consciente do desempenho, use essa abordagem de strlen() . Mais o strcspn() é uma boa alternativa.

Direto para remover o ‘\ n’ da saída fgets se toda linha tiver ‘\ n’

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

De outra forma:

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

Para um único ‘\ 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 vários cortes ‘\ 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'; } 

Você deveria tentar. Este código basicamente percorre a string até encontrar o '\ n'. Quando for encontrado, o '\ n' será substituído pelo terminador de caractere nulo '\ 0'

Note que você está comparando caracteres e não strings nesta linha, então não há necessidade de usar strcmp ():

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

desde que você estará usando aspas simples e não aspas duplas. Aqui está um link sobre aspas duplas simples vs se você quiser saber mais

 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'; 

A function abaixo é uma parte da biblioteca de processamento de strings que estou mantendo no Github. Remove e indesejados caracteres de uma string, exatamente o que você quer

 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; } 

Um exemplo de uso poderia 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 

Você pode querer verificar outras funções disponíveis, ou até mesmo contribuir para o projeto 🙂 https://github.com/fnoyanisi/zString

Tim Čas um forro é incrível para seqüências de caracteres obtidas por uma chamada para fgets, porque você sabe que eles contêm uma única nova linha no final.

Se você estiver em um contexto diferente e quiser manipular cadeias de caracteres que podem conter mais de uma nova linha, talvez esteja procurando strrspn. Não é POSIX, o que significa que você não o encontrará em todos os Unices. Eu escrevi um para minhas próprias necessidades.

 /* 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 aqueles que procuram um chomp equivalente em Perl em C, acho que é isso (chomp apenas remove a nova linha).

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

A function 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; } 

Se o uso de getline for uma opção – não negligenciando seus problemas de segurança e se você quiser chamar pointers – você pode evitar funções de string, já que o getline retorna o número de caracteres. Algo como abaixo

 #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 : Os [ problemas de segurança ] com o getline não devem ser negligenciados.

Tente 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; }