【问题标题】:How to remove \n or \t from a given string in C?如何从 C 中的给定字符串中删除 \n 或 \t?
【发布时间】:2009-10-03 23:54:41
【问题描述】:

如何在 C 中去掉所有 \n 和 \t 的字符串?

【问题讨论】:

    标签: c string


    【解决方案1】:

    这适用于我的快速而肮脏的测试。是否到位:

    #include <stdio.h>
    
    void strip(char *s) {
        char *p2 = s;
        while(*s != '\0') {
            if(*s != '\t' && *s != '\n') {
                *p2++ = *s++;
            } else {
                ++s;
            }
        }
        *p2 = '\0';
    }
    
    int main() {
        char buf[] = "this\t is\n a\t test\n test";
        strip(buf);
        printf("%s\n", buf);
    }
    

    为了安抚克里斯,这里有一个版本,它将把结果放在一个新的malloced 缓冲区中并返回它(因此它适用于文字)。您需要free 结果。

    char *strip_copy(const char *s) {
        char *p = malloc(strlen(s) + 1);
        if(p) {
            char *p2 = p;
            while(*s != '\0') {
                if(*s != '\t' && *s != '\n') {
                    *p2++ = *s++;
                } else {
                    ++s;
                }
            }
            *p2 = '\0';
        }
        return p;
    }
    

    【讨论】:

    • 在原地做这个操作是相当不安全的。如果 main() 的第一行更改为 char *buf = ...; 怎么办?如果这用于更复杂的代码并且编码人员忘记了哪些参数是可写缓冲区,哪些不是?
    • 如果你需要做一个副本,那么你总是可以先做一个副本。这样的代码还是相当简单的。
    • @Lutz,我不明白通过char*char[] 会有什么不同。另外,strip 中有一个错误:字符串不是以空值结尾的。
    • @strager:他对传递类似:char *buf = "hello\tworld" 的东西很感兴趣,这是非法的,因为您不能修改指向文字的指针。我的strip_copy 地址。
    • 但是 +1 违背了我对就地剥离效率低下的预期。
    【解决方案2】:

    如果你想用别的东西替换\n或\t,你可以使用函数strstr()。它返回一个指向具有特定字符串的函数中第一个位置的指针。例如:

    // Find the first "\n".
    char new_char = 't';
    char* pFirstN = strstr(szMyString, "\n");
    *pFirstN = new_char;
    

    您可以在循环中运行它以查找所有 \n 和 \t。

    如果您想“剥离”它们,即从字符串中删除它们,您实际上需要使用与上述相同的方法,但每次复制字符串“back”的内容当你找到 \n 或 \t 时,“this i\ns a test”变成:“this is a test”。

    您可以使用 memmove(不是 memcpy,因为 src 和 dst 指向重叠的内存)来做到这一点,如下所示:

    char* temp = strstr(str, "\t");
    // Remove \n.
    while ((temp = strstr(str, "\n")) != NULL) {
    // Len is the length of the string, from the ampersand \n, including the \n.
         int len = strlen(str);
     memmove(temp, temp + 1, len); 
    }
    

    您需要再次重复此循环以删除 \t。

    注意:这两种方法都可以在原地工作。 这可能不安全! (请阅读 Evan Teran 的 cmets 了解详细信息。。此外,这些方法效率不高,尽管它们确实为某些代码使用了库函数,而不是使用您自己的代码。

    【讨论】:

    • 这看起来对于长字符串来说效率很低。您一遍又一遍地搜索字符串(从头开始)。此外,每次找到一个字符时,您都会执行一次 strlen )。最后,每次找到一个字符时,您都在复制字符串的尾部......
    • 你是对的,效率绝对不是一个大问题(这实际上是直接来自我周围的代码的提升器,它只适用于小字符串)。我认为 strlen 实际上可以移动到字符串之外,并且每次搜索都可以从最后找到的位置而不是开头开始,从而否定了“每次搜索问题”。但是,如果他希望就地完成,我看不出有任何方法可以消除对 memmove 的需求。有什么建议吗?
    • 如果你想看到一个高效的就地条带,那么看看我的回答:-P。
    • 是的,我在发表评论后立即查看了它,现在我觉得很愚蠢:) 至少现在我的项目中有一些东西要改变......
    • 这是我在看到 Evan 的高效版本之前认为的答案。 +1 库函数 - memmove() 遗憾的是相对未知。
    【解决方案3】:

    基本上,您有两种方法可以做到这一点:您可以创建原始字符串的副本,减去所有 '\t''\n' 字符,或者您可以“就地”剥离字符串。不过,我敢打赌,第一种选择会更快,而且我向您保证它会更安全。

    所以我们要创建一个函数:

    char *strip(const char *str, const char *d);
    

    我们想使用strlen()malloc() 分配一个与str 缓冲区大小相同的新char * 缓冲区。然后我们逐个字符地遍历str。如果字符 not 包含在d 中,我们将其复制到我们的新缓冲区中。我们可以使用strchr() 之类的东西来查看每个字符是否在字符串d 中。完成后,我们有一个新缓冲区,旧缓冲区的内容减去字符串d 中的字符,所以我们只返回它。我不会给你示例代码,因为这可能是家庭作业,但这里是示例用法,向你展示它如何解决你的问题:

    char *string = "some\n text\t to strip";
    
    char *stripped = strip(string, "\t\n");
    

    【讨论】:

    • +1 用于提供学习如何操作所需的所有信息。很可能他是初学者,这些信息会很有用。
    【解决方案4】:

    这是一个 c 字符串函数,它将查找 accept 中的任何字符并返回指向该位置的指针,如果找不到则返回 NULL。

    #include <string.h>
    
    char *strpbrk(const char *s, const char *accept);
    

    例子:

    char search[] = "a string with \t and \n";
    
    char *first_occ = strpbrk( search, "\t\n" );
    

    first_occ 将指向 \t 或 search 中的第 15 个字符。您可以替换然后再次调用以循环遍历,直到全部替换为止。

    【讨论】:

      【解决方案5】:

      我喜欢让标准库做尽可能多的工作,所以我会使用与 Evan 的解决方案类似的东西,但使用 strspn()strcspn()

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      
      #define SPACE " \t\r\n"
      
      static void strip(char *s);
      static char *strip_copy(char const *s);
      
      int main(int ac, char **av)
      {
          char s[] = "this\t is\n a\t test\n test";
          char *s1 = strip_copy(s);
          strip(s);
          printf("%s\n%s\n", s, s1);
          return 0;
      }
      
      static void strip(char *s)
      {
          char *p = s;
          int n;
          while (*s)
          {
              n = strcspn(s, SPACE);
              strncpy(p, s, n);
              p += n;
              s += n + strspn(s+n, SPACE);
          }
          *p = 0;
      }
      
      static char *strip_copy(char const *s)
      {
          char *buf = malloc(1 + strlen(s));
          if (buf)
          {
              char *p = buf;
              char const *q;
              int n;
              for (q = s; *q; q += n + strspn(q+n, SPACE))
              {
                  n = strcspn(q, SPACE);
                  strncpy(p, q, n);
                  p += n;
              }
              *p++ = '\0';
              buf = realloc(buf, p - buf);
          }
          return buf;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-06
        • 1970-01-01
        • 2019-10-24
        • 2021-03-04
        • 2013-07-22
        • 2011-12-08
        • 2011-05-10
        • 2011-10-15
        相关资源
        最近更新 更多