C程序从字符串中删除所有不必要的空格

时间:2016-08-15 14:19:51

标签: c arrays pointers char

我尝试创建一个C函数,从字符串中删除所有不必要的空格。举个例子:

    Hi       my      name is  Leon   .

在函数调用之后,它应如下所示: Hi my name is Leon. 但是我的程序总是在最后一个单词后面留一个空格,所以它看起来像这样:

Hi my name is Leon .

有关如何修复的任何想法? 这是代码:

char *DeleteSpaces(char *str) {
int blank = 1;
char *poc, *start = str, *q;
q = str;
while (*q == ' ') q++;
    poc = str;
    while (*poc++ = *q++);
while (*str != '\0') {
    q = str;
    if (*str == ' ') {
        if ((blank >= 1 && *(str-1) == ' ')) {
            poc = str;
            while (*poc == ' ') {
                poc++;
            }
            q = str;
            while(*poc != '\0') {
                *q++ = *poc++;
            }
            *q = '\0';
            blank = 0;

        }
        blank++;
    }
    else if (blank == 1)
        blank = 0;
    str++;
}
str--;
if (str == ' ') *str = '\0';

return start;
}

3 个答案:

答案 0 :(得分:2)

从字符串中删除空格时,需要考虑许多微妙的问题。一个重要问题是保留指向原始开头的指针,因此如果原始动态分配,您不会失去free内存的能力从而导致内存泄漏。

其次,您有三个基本的重建索引考虑因素:(1)前导空格; (2)交错空白; (3)结束后的空格。 (加上你想要构建的任何自定义案例,比如在'.'之前修剪任何空格)。你可以在日常工作中按顺序接受它们。

虽然您现在只是查看' 'space)字符,但您没有理由不同时处理所有空白ctype.h标头提供了isspace函数(宏)来做到这一点。

将这些部分放在一起,您可以执行以下操作rmxws删除多余的空格):

char *rmxws (char *s)
{
    if (!s) return NULL;             /* valdiate string not NULL */
    if (!*s) return s;                    /* handle empty string */

    char *p = s, *wp = s;            /* pointer and write-pointer */

    while (*p) {
        if (isspace(*p)) {                         /* test for ws */
            if (wp > s)               /* ignore leading ws, while */
                *wp++ = *p;         /* preserving 1 between words */
            while (*p && isspace (*p))         /* skip remainder  */
                p++;
            if (!*p)                     /* bail on end-of-string */
                break;
        }
        if (*p == '.')       /* handle space between word and '.' */
            while (wp > s && isspace (*(wp - 1)))
                wp--;
        *wp++ = *p;                            /* use non-ws char */
        p++;
    }
    while (wp > s && isspace (*(wp - 1)))     /* trim trailing ws */
        wp--;
    *wp = 0;    /* nul-terminate */

    return s;
}

将它与一个简短的例子放在一起,您可以按如下方式进行测试:

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

char *rmxws (char *s);

int main (int argc, char **argv) {

    char *s = argc > 1 ? argv[1] : (char []){ " Testing  1 2  3. . .  "};
    printf ("\n original : '%s'\n", s);
    printf (" trimmed  : '%s'\n\n", rmxws (s));

    return 0;
}

char *rmxws (char *s)
{
    if (!s) return NULL;             /* valdiate string not NULL */
    if (!*s) return s;                    /* handle empty string */

    char *p = s, *wp = s;            /* pointer and write-pointer */

    while (*p) {
        if (isspace(*p)) {                         /* test for ws */
            if (wp > s)               /* ignore leading ws, while */
                *wp++ = *p;         /* preserving 1 between words */
            while (*p && isspace (*p))         /* skip remainder  */
                p++;
            if (!*p)                     /* bail on end-of-string */
                break;
        }
        if (*p == '.')       /* handle space between word and '.' */
            while (wp > s && isspace (*(wp - 1)))
                wp--;
        *wp++ = *p;                            /* use non-ws char */
        p++;
    }
    while (wp > s && isspace (*(wp - 1)))     /* trim trailing ws */
        wp--;
    *wp = 0;    /* nul-terminate */

    return s;
}

示例使用/输出

$ ./bin/trimxsws "    Hi       my      name is  Leon   .  "

 original : '    Hi       my      name is  Leon   .  '
 trimmed  : 'Hi my name is Leon.'

或只是

$ ./bin/trimxsws

 original : ' Testing  1 2  3. . .  '
 trimmed  : 'Testing 1 2 3...'

仔细看看,如果您有任何其他问题,请告诉我。

答案 1 :(得分:1)

考虑到只有当非空格字符跟在非前导空格时,才需要在dest中保存空格。简化循环。

char *DeleteSpaces(char *str) {
  char *start = str;
  char *dest = str;

  // skip leading spaces
  while (*str == ' ') str++;

  char previous = 0;
  char ch;

  while ((ch = *str++) != '\0') {
    if (ch != ' ') {
      if (previous == ' ') {
        *dest++ = previous;
      }
      *dest++ = ch;
    }
    previous = ch;
  }

  *dest = '\0';
  return start;
}

答案 2 :(得分:0)

以下代码

  1. 似乎有用,我没有经过严格的测试。
  2. 干净地编译
  3. 将原始指针返回给char字符串
  4. 执行功能,inplace
  5. 现在是代码

    #include <ctype.h>
    
    char *DeleteSpaces(char *str) 
    {
        char * src = str;
        char * dest = str;
    
        int inBlank = 0;
    
        while( *src )
        {
            if ( isalpha( *src ) )
            {
                *dest = *src;
                dest++;
                src++;
                inBlank = 0;
            }
    
            else if( ispunct(*src) )
            {
                if( inBlank )
                {
                    dest--;
                }
    
                *dest = *src;
                dest++;
                src++;
                inBlank = 0; 
            }
    
            else if( isspace( *src ) )
            {
                if( inBlank )
                {
                    src++;
                }
    
                else
                {
                    inBlank =1;
                    *dest = *src;
                    dest++;
                    src++;  
                }           
            }
        }
    
        *dest = '\0';
    
        return str;
    }