在C语言中将多个空格替换为单个空格

3

我想将字符串中的多个空格替换为单个空格,但是我的以下代码不起作用。逻辑上出了什么问题?

#include<stdio.h>
#include<string.h>
main()
{
char input[100];
int i,j,n,z=0;
scanf("%d",&n);
z=n;
for(i=0;i<n;i++)
scanf("%c",&input[i]);
for(i=0;i<n;i++)
{
    if(input[i]==' ' && (input[i+1]==' ' || input[i-1]==' '))
    {
        --z;
        for(j=i;j<n;j++)
        input[j]=input[j+1];
    }
}
for(i=0;i<z;i++)
    printf("%c",input[i]);
printf("\n");
}

1
scanf 会出现一些问题。建议使用 gets 或者 scanf("%s",input) - Navnath Godse
错误的 if(input[i]==' ' && (input[i+1]==' ' || input[i-1]==' ')) - BLUEPIXY
@BLUEPIXY,出了什么问题? - Jaskaran S.P
see sample code of my answer - BLUEPIXY
@Navnath:请不要建议使用gets()。因为它已经从2011年起被C标准废弃,无法安全易用。建议使用fgets()来读取交互式用户输入,这是完全合理的选择。 - pmg
9个回答

7
我会这样做:
void replace_multi_space_with_single_space(char *str)
{
    char *dest = str;  /* Destination to copy to */

    /* While we're not at the end of the string, loop... */
    while (*str != '\0')
    {
        /* Loop while the current character is a space, AND the next
         * character is a space
         */
        while (*str == ' ' && *(str + 1) == ' ')
            str++;  /* Just skip to next character */

       /* Copy from the "source" string to the "destination" string,
        * while advancing to the next character in both
        */
       *dest++ = *str++;
    }

    /* Make sure the string is properly terminated */    
    *dest = '\0';
}

当然,以上的函数需要你正确终止字符串,而目前你没有这样做。
上述函数的基本功能是将字符串复制到自身。唯一的例外是在空格时,多个空格会被简单地丢弃。
由于该函数修改源字符串,因此无法用于字符串字面量。

2

如果(input[i]==' ' && (input[i+1]==' ' || input[i-1]==' '))

情况 " 1 3" : 当 i == 0 时,访问 input[i-1] 超出范围

scanf("%d",&n);

保留换行符,(input[0] <-- '\n')

修改为

scanf("%d%*c",&n);

#include <stdio.h>

char* uniq_spc(char* str){
    char *from, *to;
    int spc=0;
    to=from=str;
    while(1){
        if(spc && *from == ' ' && to[-1] == ' ')
            ++from;
        else {
            spc = (*from==' ')? 1 : 0;
            *to++ = *from++;
            if(!to[-1])break;
        }
    }
    return str;
}

int main(){
    char input[]= "  abc   de  f  ";

    printf("\"%s\"\n", uniq_spc(input));//output:" abc de f "
    return 0;
}

你的答案(我看到其他人也有)非常好,但稍微解释一下会更有帮助,不仅对 OP,也对其他人。 :) - Grijesh Chauhan
to[-1]引入了spc标志以避免序列范围。 - BLUEPIXY

2
< p>你遇到了一些问题,是因为scanf在读取你输入长度n后会读取你加上的\n符号。因此,在for循环退出时,你将会错过最后一个字符。已给出的答案已经足够好了。但如果你想按照自己的逻辑进行操作,请尝试以下方法:

void main()
{
    char input[100];
    int i = 0,j,n = 0;
    while ((input[n] = getchar()) != '\n') {
        n++;
    }
    input[n] = '\0';
    while (i < n)
    {
        if(input[i]==' ' && (input[i+1]==' ' || input[i-1]==' '))
        {
            for(j=i;j<n;j++)
            input[j]=input[j+1];
            n--;
        }
        else
        {
            i++;
        }
    }
    printf("%s\n",input);
    printf("\n");
}

在我看来,这个解决方案的时间复杂度是O(n^2)。有一个O(n)的解决方案。 - shlomi33

1
为什么要把它搞得比必须要复杂?您可以使用 strtok 来检查单个空格并忽略它们。然后,您可以使用 strcat 将字符串连接成完整的句子,然后完成了。
这是我做的方式:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int main(void) {
    char *pch;
    char sentence[1000];
    char without[1000];

    printf("Sentence: ");
    fgets(sentence,1000, stdin);
    strtok(sentence, "\n"); // remove any newlines
    pch = strtok(sentence, " ");
    while(pch != NULL) {
      strcat(without, pch);
      strcat(without, " \0");
      pch = strtok(NULL, " ");
    }
    without[strlen(without)-1] = '\0'; // remove extra whitespace at the end
    printf("|%s|\n",without);
    return 0;
}

1
您可以尝试这段简单的代码:

你不能尝试这个简单的代码:

#include <stdio.h>

#define IN 1
#define OUT 0

int main() {
  int c, spaces, state;

  spaces = 0;
  state = OUT;  
  while ((c = getchar()) != EOF) {

      if ( c == ' ') {
           ++spaces;
           state = OUT;
       }
      else if (state == OUT) {
          state = IN;
          spaces = 0;
      }
      if (c == ' ' && spaces > 1 && state == OUT)
          c = 0;            
      putchar(c);
  }
  return 0;
}

1
#include <stdio.h>
#include <stdlib.h>
void remove_blanks(char* s);

int main()
{
    char const s[] = {'1',' ',' ','2',' ',' ','3'};
    remove_blanks(s);
    printf("%s",s);
    return 0;
}

void remove_blanks(char* s){
    int i=0, delta=0, cnt=0;

    for (i=0;s[i];++i){
        if (s[i]==' ') cnt++;
        if (cnt>1){
            delta+=1;
            cnt=0;
        }
        s[i-delta]=s[i];
        if(delta>0) s[i]='\0';

    }
}

0
#include<stdio.h>
#include<string.h>
int main(void)
    {
        char input[1000];
        int i=0;
        gets(input); 
        for(i=0;input[i]!='\0';i++)
        {
            if(input[i]!=' ' || input[i+1]!=' ')
                printf("%c",input[i]);
        }
        return 0;
    }

0
你需要修复以下的for循环。你的for循环的限制应该是z而不是n
for(j=i;j<n;j++)
input[j]=input[j+1];

for(j=i;j<z;j++)
input[j]=input[j+1];

顺便提一下:通过你的scanf()(读取字符)获取的第一个字符是换行符(\n)。这个换行符来自于十进制(%d)的第一个scanf()


0

最简单的方法是使用 string.h 库中的两个函数:

void strRemoveBlanks(char* _s){
    char* ptr = NULL;
    while ((ptr = strstr(_s, "  ")) != NULL)
        memmove(ptr, ptr + 1, strlen(ptr));
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接