从C字符串中删除多余的空格?

时间:2009-09-22 04:40:22

标签: c string whitespace

我已经在C字符串数组中读了几行文本。这些行有任意数量的制表符或空格分隔的列,我试图弄清楚如何删除它们之间的所有额外空格。最终目标是使用strtok来分解列。这是列的一个很好的例子:

Cartwright   Wendy    93
Williamson   Mark     81
Thompson     Mark     100
Anderson     John     76
Turner       Dennis   56

如何消除列之间的所有空格或制表符,以便输出看起来像这样?

Cartwright Wendy 93

或者,我可以用不同的字符替换列之间的所有空格以便使用strtok吗?像这样的东西?

Cartwright#Wendy#93

编辑:多个很棒的答案,但必须选择一个。感谢所有人的帮助。

9 个答案:

答案 0 :(得分:11)

如果我可以发出“你做错了”的意见,为什么不在阅读时消除空白呢?使用fscanf("%s", string);读取“单词”(非空格),然后读取空格。如果是空格或制表符,请继续阅读一行“数据”。如果是换行符,请启动新条目。在C语言中,最简单的方法是将数据转换为可以尽快使用的格式,而不是尝试进行繁重的文本操作。

答案 1 :(得分:5)

为什么不直接使用strtok()?无需修改输入

您需要做的就是重复strtok(),直到获得3个非太空令牌然后就完成了!

答案 2 :(得分:2)

编辑:我最初有一个malloced工作区,我可能会更清楚。但是,没有额外内存这样做几乎一样简单,而且我在评论和个人即时通讯中被推,所以,这里来了......: - )

void squeezespaces(char* row, char separator) {
  char *current = row;
  int spacing = 0;
  int i;

  for(i=0; row[i]; ++i) {
    if(row[i]==' ') {
      if (!spacing) {
        /* start of a run of spaces -> separator */
        *current++ = separator
        spacing = 1;
      }
    } else {
      *current++ = row[i];
      spacing = 0;
  }
  *current = 0;    
}

答案 3 :(得分:2)

以下代码修改了字符串;如果您不想销毁原始输入,可以传递第二个缓冲区以接收修改后的字符串。应该是相当不言自明的:

#include <stdio.h>
#include <string.h>

char *squeeze(char *str)
{
  int r; /* next character to be read */
  int w; /* next character to be written */

  r=w=0;
  while (str[r])
  {
    if (isspace(str[r]) || iscntrl(str[r]))
    {
      if (w > 0 && !isspace(str[w-1]))
        str[w++] = ' ';
    }
    else
      str[w++] = str[r];
    r++;
  }
  str[w] = 0;
  return str;
}

int main(void)
{
  char test[] = "\t\nThis\nis\ta\b     test.";
  printf("test = %s\n", test);
  printf("squeeze(test) = %s\n", squeeze(test));
  return 0;
}

答案 4 :(得分:1)

char* trimwhitespace(char *str_base) {
    char* buffer = str_base;
    while((buffer = strchr(str_base, ' '))) {
        strcpy(buffer, buffer+1);
    }

    return str_base;
}

答案 5 :(得分:0)

您可以读取一行然后扫描它以找到每列的开头。然后使用您想要的列数据。

#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define MAX_COL 3
#define MAX_REC 512

int main (void)
{
    FILE *input;
    char record[MAX_REC + 1];
    char *scan;
    const char *recEnd;
    char *columns[MAX_COL] = { 0 };
    int colCnt;

    input = fopen("input.txt", "r");

    while (fgets(record, sizeof(record), input) != NULL)
    {
        memset(columns, 0, sizeof(columns));  // reset column start pointers

        scan = record;
        recEnd = record + strlen(record);

        for (colCnt = 0; colCnt < MAX_COL; colCnt++ )
        {
          while (scan < recEnd && isspace(*scan)) { scan++; }  // bypass whitespace
          if (scan == recEnd) { break; }
          columns[colCnt] = scan;  // save column start
          while (scan < recEnd && !isspace(*scan)) { scan++; }  // bypass column word
          *scan++ = '\0';
        }

        if (colCnt > 0)
        {
            printf("%s", columns[0]);
            for (int i = 1; i < colCnt; i++)
            {
             printf("#%s", columns[i]);
            }
            printf("\n");
        }
    }

    fclose(input);
}

注意,代码仍然可以使用一些robust -ification:检查文件错误w / ferror;确保eof被击中;确保处理完整记录(所有列数据)。通过使用链表而不是固定数组也可以使其更加灵活,并且可以修改为不假设每列只包含一个单词(只要列由特定字符分隔)。

答案 6 :(得分:0)

这是一个替代函数,用于挤出isspace()<ctype.h>定义的重复空格字符。它返回'squidged'字符串的长度。

#include <ctype.h>

size_t squidge(char *str)
{
    char *dst = str;
    char *src = str;
    char  c;
    while ((c = *src++) != '\0')
    {
        if (isspace(c))
        {
            *dst++ = ' ';
            while ((c = *src++) != '\0' && isspace(c))
                ;
            if (c == '\0')
                break;
        }
        *dst++ = c;
    }
    *dst = '\0';
    return(dst - str);
}

#include <stdio.h>
#include <string.h>

int main(void)
{
    char buffer[256];
    while (fgets(buffer, sizeof(buffer), stdin) != 0)
    {
        size_t len = strlen(buffer);
        if (len > 0)
            buffer[--len] = '\0';
        printf("Before: %zd <<%s>>\n", len, buffer);
        len = squidge(buffer);
        printf("After:  %zd <<%s>>\n", len, buffer);
    }
    return(0);
}

答案 7 :(得分:0)

我对John Bode的改进做了一些改进,以删除尾随的空格:

#include <ctype.h>

char *squeeze(char *str)
{
  char* r; /* next character to be read */
  char* w; /* next character to be written */
  char c;
  int sp, sp_old = 0;

  r=w=str;

  do {
    c=*r;
    sp = isspace(c);
    if (!sp) {
      if (sp_old && c) {
        // don't add a space at end of string
        *w++ = ' ';
      }
      *w++ = c;
    }
    if (str < w) {
      // don't add space at start of line
      sp_old = sp;
    }
    r++;
  }
  while (c);

  return str;
}

#include <stdio.h>

int main(void)
{
  char test[] = "\t\nThis\nis\ta\f     test.\n\t\n";
  //printf("test = %s\n", test);
  printf("squeeze(test) = '%s'\n", squeeze(test));
  return 0;
}

宽单峰

答案 8 :(得分:0)

下面的代码只是简单地输入字符,然后检查每个字符是否有空格多次跳过它,否则它会打印字符。 您也可以使用相同的逻辑选项卡。 希望它有助于解决您的问题。如果此代码有任何问题,请告诉我。

    int c, count = 0;
    printf ("Please enter your sentence\n");
    while ( ( c = getchar() ) != EOF )  {
        if ( c != ' ' )  {
            putchar ( c );
            count = 0;
        }
        else  {
            count ++;
            if ( count > 1 )
                ;    /* Empty if body */
            else
                putchar ( c );
         }
     }
}