从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'; }
使用buffer
和len
。
这个方法对于后面的代码有一个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++; }