从fgets()input中删除尾随的换行符

我试图从用户获取一些数据,并将其发送到gcc中的另一个函数。 代码是这样的。

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

不过,我发现最后还是换了一个换行符。 所以如果我inputJohn它最终发送John\n 。 如何删除\n并发送正确的string。

稍微丑陋的方式:

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

有点奇怪的方式:

 strtok(Name, "\n"); 

请注意,如果用户input一个空string(即只按下Enter), strtok函数不能按预期工作。 它使\n字符保持不变。

当然也有其他的。

也许最简单的解决scheme使用我最喜欢的鲜为人知的函数之一strcspn()

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

如果你想要它也处理'\r' (比如,如果stream是二进制的):

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

该函数计算字符数直到遇到'\r''\n' (换句话说,它find第一个'\r''\n' )。 如果它什么也没有发生,就停在'\0' (返回string的长度)。

请注意,即使没有换行,这也可以正常工作,因为strcspn停在'\0' 。 在这种情况下,整个行只是用'\0'代替'\0'

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

一种快速方法,通过fgets()从string中删除潜在的'\n'
它使用strlen()和2个testing。

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

使用bufferlen


这个方法对于后面的代码有一个len值的副作用。 它可以比strchr(Name, '\n')快得多。 参考 YMMV,但这两种方法的工作。

buffer不会以"\n"结尾2种情况下:
A)该行对于buffer来说太长,所以只有'\n'前面的char被保存在buffer
B)文件的最后一行没有以'\n'结尾。

如果input内嵌有空字符'\0' ,则strlen()报告的长度将不包含'\n'位置。


其他方法问题:

strtok(buffer, "\n");buffer"\n"时,无法删除'\n'

fgets()读取的第一个char'\0'的情况下,以下情况很less出现。 当input以embedded的'\0'开始时会发生这种情况。 然后, buffer[len -1]变成buffer[SIZE_MAX]肯定在buffer的合法范围之外。 黑客可能会尝试或发现愚蠢地阅读UTF16文本文件。

 size_t len = strlen(buffer); if (buffer[len - 1] == '\n') { // FAILS when len == 0 buffer[len -1] = '\0'; } 

sprintf(buffer,"%s",buffer); 是未定义的行为: Ref 。 此外,它不保存任何前导,分隔或结尾的空白。

[编辑] 1 buffer[strcspn(buffer, "\n")] = 0; 除了与strlen()方法相比的性能之外。 修剪性能通常不是问题,因为代码正在做I / O – CPU时间的黑洞。 如果下面的代码需要string的长度或高度的性能意识,请使用strlen()方法。 否则strcspn()是一个很好的select。

如果每行都有'\ n',直接从fgets输出中删除'\ n'

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

除此以外:

 void remove_newline_ch(char *line) { int new_line = strlen(line) -1; if (line[new_line] == '\n') line[new_line] = '\0'; } 
 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'; 

对于单个'\ 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'; } } 

对于多个“\ 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; } } 

最简单的方法是:

 while(fgets(Name, 512, fp) != NULL) { if (Name[0] == '\n' || Name[0] == '\r') continue; strtok(Name, "\n"); ... } 

下面的函数是我在Github上维护的string处理库的一部分。 它从string中删除和不需要的字符,正是你想要的

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

一个示例用法可能是

 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 

你可能想检查其他可用的function,甚至有助于项目:) https://github.com/fnoyanisi/zString

对于通过调用fgets获得的string,TimČas单行是惊人的,因为你知道它们在最后包含一个换行符。

如果您处于不同的上下文中,并且想要处理可能包含多个换行符的string,那么您可能正在寻找strrspn。 这不是POSIX,这意味着你不会在所有的Unices上find它。 我为自己的需要写了一个。

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

对于那些在C中寻找Perl chomp等价物的人来说,我认为是这样的(chomp只消除了后面的换行符)。

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

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

fgets处理string时,我个人使用下面的方法:

 if(str[strlen(str) - 1] == '\n') { str[strlen(str) - 1] = '\0'; } 

你也可以使用其他人在他们以前的答案中提到的function,但我喜欢这种方法的简单性。

  for(int i = 0; i < strlen(Name); i++ ) { if(Name[i] == '\n') Name[i] = '\0'; } 

你应该试试看。 这段代码基本上是循环遍历string,直到find'\ n'。 当发现'\ n'将被replace为空字符终止符'\ 0'

请注意,您在这一行中比较字符而不是string,则不需要使用strcmp():

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

因为你将使用单引号而不是双引号。 如果你想知道更多的信息, 这里有一个关于单引号和双引号的链接

获得用户input后获得“\ n”的最大原因是您正在使用scanf(); 。 起初我也有同样的问题,但我意识到, getch(); 对于这类问题是一个很好的select,但是你必须使用一个转义字符,如*或%或其他类似的东西来表示input结束。

尝试这个:

 char var[50]; int pos=0; printf("Enter your name:"); while(var[pos]!="%") { var[pos]=getch(); pos++; }