【问题标题】:C program to delete all unnecessary blanks from a string [closed]C程序从字符串中删除所有不必要的空格[关闭]
【发布时间】:2016-08-15 14:19:51
【问题描述】:

我试图创建一个 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;
}

【问题讨论】:

  • 您显示的代码有什么问题?你有构建错误吗?运行时崩溃?出乎意料的结果?请详细说明。另外,你如何调用这个函数?你传递什么作为论点?请read about how to ask good questions,并学习如何创建Minimal, Complete, and Verifiable Example
  • 您将一系列空间压缩成一个空间。如果要在 . 之前完全删除空格,则需要添加逻辑。
  • 请研究一下 cmets 的用途。提示:你的代码很难理解,不仅是因为格式,还因为缺少解释。
  • 你没有考虑标点符号;您需要一些额外的逻辑来删除字母和句点(或逗号、分号或问号等)之间的 all 空格。此外,您的代码似乎有点复杂。
  • 发布“为什么我的代码不起作用”问题时,请发布干净编译和运行的代码,即包括调用包含问题的函数的main() 函数。包括所需的#include 语句,以便可以编译代码。

标签: c arrays pointers char


【解决方案1】:

在从字符串中删除 空格 时需要考虑许多微妙的问题。一个重要的问题是保留指向原件开始的指针,因此如果原件是动态分配的,您不会失去稍后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...'

检查一下,如果您有任何其他问题,请告诉我。

【讨论】:

    【解决方案2】:

    请考虑,仅当非空格字符跟随非前导空格时,才需要在 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;
    }
    

    【讨论】:

      【解决方案3】:

      以下代码

      1. 似乎有效,我没有严格测试过。
      2. 干净编译
      3. 返回指向 char 字符串的原始指针
      4. 就地执行功能

      现在是代码

      #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;
      }
      

      【讨论】:

        猜你喜欢
        • 2014-07-14
        • 2023-03-25
        • 2019-11-25
        • 2014-04-01
        • 1970-01-01
        • 2016-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多