首页 文章

从fgets()输入中删除尾随换行符

提问于
浏览
174

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

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

但是,我发现它最后有一个换行符 \n 字符 . 因此,如果我输入 John ,它最终会发送 John\n . 如何删除 \n 并发送正确的字符串 .

12 回答

  • 80

    有点丑陋的方式:

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

    有点奇怪的方式:

    strtok(Name, "\n");
    

    请注意,如果用户输入空字符串(即仅按Enter键), strtok 函数将无法按预期工作 . 它使 \n 字符保持不变 .

    当然还有其他一些 .

  • 0

    也许最简单的解决方案使用我最喜欢的一个鲜为人知的函数,strcspn()

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

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

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

    该函数计算字符数,直到它达到 '\r''\n' (换句话说,它找到第一个 '\r''\n' ) . 如果它没有击中任何东西,它会在 '\0' 处停止(返回字符串的长度) .

    请注意,即使没有换行,这也能正常工作,因为 strcspn'\0' 处停止 . 在这种情况下,整条线只是用 '\0' 替换 '\0' .

  • -1
    size_t ln = strlen(name) - 1;
    if (*name && name[ln] == '\n') 
        name[ln] = '\0';
    
  • 4
    for(int i = 0; i < strlen(Name); i++ )
    {
        if(Name[i] == '\n') Name[i] = '\0';
    }
    

    你应该试一试 . 此代码基本上循环遍历字符串,直到找到'\ n' . 当发现'\ n'将被空字符终止符'\ 0'替换时

    请注意,您正在比较字符和不是这一行中的字符串,那么就不需要使用strcmp():

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

    因为你将使用单引号而不是双引号 . Here's如果您想了解更多信息,请参阅有关单引号和双引号的链接

  • -1

    试试这个:

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

    以下是从 fgets() 保存的字符串中删除潜在 '\n' 的快速方法 .
    它使用 strlen() ,有2个测试 .

    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') 更快 . Ref YMMV,但两种方法都有效 .


    buffer ,原始 fgets() 在某些情况下不会包含在 "\n" 中:
    A) buffer 的行太长,因此只有 '\n' 之前的 char 保存在 buffer 中 . 未读的字符仍保留在流中 .
    B)文件中的最后一行没有以 '\n' 结尾 .

    如果输入在某处嵌入了空字符 '\0' ,则 strlen() 报告的长度将不包括 '\n' 位置 .


    其他一些答案的问题:

    buffer"\n"

    • strtok(buffer, "\n"); 无法删除 '\n' . 从这个answer - 在这个答案之后修改了警告这个限制 .

    • fgets() 读取的第一个 char'\0' 的极少数情况下,以下情况失败 . 输入以嵌入的 '\0' 开头时会发生这种情况 . 然后 buffer[len -1] 变得 buffer[SIZE_MAX] 肯定在 buffer 的合法范围之外访问内存 . 黑客可能在愚蠢地阅读UTF16文本文件时尝试或找到的东西 . 当这个答案写完时,这就是answer的状态 . 后来非OP编辑了它,包括像这个答案检查 "" 的代码 .

    size_t len = strlen(buffer);
    if (buffer[len - 1] == '\n') {  // FAILS when len == 0
      buffer[len -1] = '\0';
    }
    
    • sprintf(buffer,"%s",buffer); 是未定义的行为:Ref . 此外,它不会保存任何前导,分隔或尾随空格 . 现在deleted .

    • [稍后编辑answer]与 strlen() 方法相比,1衬里 buffer[strcspn(buffer, "\n")] = 0; 除性能外没有问题 . 在代码正在进行I / O时,修整性能通常不是问题 - 这是CPU时间的黑洞 . 如果以下代码需要字符串的长度或具有高度的性能意识,请使用此 strlen() 方法 . 否则 strcspn() 是一个很好的选择 .

  • -1

    如果每行都有'\ 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';
    }
    
  • 116

    单个'\ n'trmming,

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

    多个'\ n'修剪,

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

    TimČas的一个班轮对于通过调用fgets获得的字符串来说是惊人的,因为你知道它们最后包含一个换行符 .

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

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

    如果使用 getline 是一个选项 - 不要忽视它的安全问题,如果你想支持指针 - 你可以避免字符串函数,因为 getline 返回字符数 . 像下面的东西

    #include<stdio.h>
    #include<stdlib.h>
    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;
    }
    

    注意:不应忽视getline的[安全问题] .

  • 318
    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';
    
  • -1

    下面的函数是我在Github上维护的字符串处理库的一部分 . 它会删除字符串中不需要的字符,这正是您想要的

    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
    

    您可能想要检查其他可用功能,甚至可以参与项目:) https://github.com/fnoyanisi/zString

相关问题