简体   繁体   English

从 C 中的字符串中删除空格

[英]Remove spaces from a string in C

从 C 中的字符串中删除空格的最简单和最有效的方法是什么?

Easiest and most efficient don't usually go together…最简单和最有效的方法通常不会同时存在……

Here's a possible solution for in-place removal:这是就地移除的可能解决方案:

void remove_spaces(char* s) {
    char* d = s;
    do {
        while (*d == ' ') {
            ++d;
        }
    } while (*s++ = *d++);
}

Here's a very compact, but entirely correct version:这是一个非常紧凑但完全正确的版本:

do while(isspace(*s)) s++; while(*d++ = *s++);

And here, just for my amusement, are code-golfed versions that aren't entirely correct, and get commenters upset.在这里,只是为了我的娱乐,代码高尔夫版本不完全正确,让评论者感到不安。

If you can risk some undefined behavior, and never have empty strings, you can get rid of the body:如果你可以冒险一些未定义的行为,并且永远不会有空字符串,你可以摆脱身体:

while(*(d+=!isspace(*s++)) = *s);

Heck, if by space you mean just space character:哎呀,如果你说的空格只是空格字符:

while(*(d+=*s++!=' ')=*s);

Don't use that in production :)不要在生产中使用它:)

As we can see from the answers posted, this is surprisingly not a trivial task.正如我们从发布的答案中看到的那样,这令人惊讶地不是一项微不足道的任务。 When faced with a task like this, it would seem that many programmers choose to throw common sense out the window, in order to produce the most obscure snippet they possibly can come up with.当面对这样的任务时,似乎许多程序员选择将常识抛诸脑后,以产生他们可能想出的最晦涩的片段。

Things to consider:需要考虑的事项:

  • You will want to make a copy of the string, with spaces removed.您需要复制该字符串,并删除空格。 Modifying the passed string is bad practice, it may be a string literal.修改传递的字符串是不好的做法,它可能是字符串文字。 Also, there are sometimes benefits of treating strings as immutable objects .此外,将字符串视为不可变对象有时也有好处。
  • You cannot assume that the source string is not empty.您不能假设源字符串不为空。 It may contain nothing but a single null termination character.它可能只包含一个空终止字符。
  • The destination buffer can contain any uninitialized garbage when the function is called.调用函数时,目标缓冲区可以包含任何未初始化的垃圾。 Checking it for null termination doesn't make any sense.检查它是否为空终止没有任何意义。
  • Source code documentation should state that the destination buffer needs to be large enough to contain the trimmed string.源代码文档应说明目标缓冲区需要足够大以包含修剪后的字符串。 Easiest way to do so is to make it as large as the untrimmed string.最简单的方法是使它与未修剪的字符串一样大。
  • The destination buffer needs to hold a null terminated string with no spaces when the function is done.当函数完成时,目标缓冲区需要保存一个没有空格的空终止字符串。
  • Consider if you wish to remove all white space characters or just spaces ' ' .考虑是否要删除所有空白字符或仅删除空格' '
  • C programming isn't a competition over who can squeeze in as many operators on a single line as possible. C 编程不是关于谁能在一行中挤入尽可能多的运算符的竞争。 It is rather the opposite, a good C program contains readable code (always the single-most important quality) without sacrificing program efficiency (somewhat important).恰恰相反,一个好的 C 程序包含可读的代码(始终是最重要的质量),而不会牺牲程序效率(有些重要)。
  • For this reason, you get no bonus points for hiding the insertion of null termination of the destination string, by letting it be part of the copying code.出于这个原因,通过让目标字符串成为复制代码的一部分来隐藏目标字符串的空终止插入,您不会获得任何奖励积分。 Instead, make the null termination insertion explicit, to show that you haven't just managed to get it right by accident.相反,让空终止插入显式,以表明您不是偶然地设法做到了正确。

What I would do:我会怎么做:

void remove_spaces (char* restrict str_trimmed, const char* restrict str_untrimmed)
{
  while (*str_untrimmed != '\0')
  {
    if(!isspace(*str_untrimmed))
    {
      *str_trimmed = *str_untrimmed;
      str_trimmed++;
    }
    str_untrimmed++;
  }
  *str_trimmed = '\0';
}

In this code, the source string "str_untrimmed" is left untouched, which is guaranteed by using proper const correctness.在此代码中,源字符串“str_untrimmed”保持不变,这是通过使用适当的常量正确性来保证的。 It does not crash if the source string contains nothing but a null termination.如果源字符串只包含一个空终止符,它不会崩溃。 It always null terminates the destination string.它始终为 null 终止目标字符串。

Memory allocation is left to the caller.内存分配留给调用者。 The algorithm should only focus on doing its intended work.该算法应该只专注于完成其预期的工作。 It removes all white spaces.它删除所有空格。

There are no subtle tricks in the code.代码中没有任何微妙的技巧。 It does not try to squeeze in as many operators as possible on a single line.它不会试图在一行中挤入尽可能多的运算符。 It will make a very poor candidate for the IOCCC .它将成为IOCCC 的一个非常糟糕的候选人。 Yet it will yield pretty much the same machine code as the more obscure one-liner versions.然而,它将产生与更晦涩的单行版本几乎相同的机器代码。

When copying something, you can however optimize a bit by declaring both pointers as restrict , which is a contract between the programmer and the compiler, where the programmer guarantees that the destination and source are not the same address.但是,在复制某些内容时,您可以通过将两个指针声明为restrict来优化一点,这是程序员和编译器之间的契约,程序员保证目标和源地址不同。 This allows more efficient optimization, since the compiler can then copy straight from source to destination without temporary memory in between.这允许更有效的优化,因为编译器可以直接从源复制到目标,中间没有临时内存。

In C, you can replace some strings in-place, for example a string returned by strdup():在 C 中,您可以就地替换一些字符串,例如 strdup() 返回的字符串:

char *str = strdup(" a b c ");

char *write = str, *read = str;
do {
   if (*read != ' ')
       *write++ = *read;
} while (*read++);

printf("%s\n", str);

Other strings are read-only, for example those declared in-code.其他字符串是只读的,例如那些在代码中声明的字符串。 You'd have to copy those to a newly allocated area of memory and fill the copy by skipping the spaces:您必须将它们复制到新分配的内存区域并通过跳过空格来填充副本:

char *oldstr = " a b c ";

char *newstr = malloc(strlen(oldstr)+1);
char *np = newstr, *op = oldstr;
do {
   if (*op != ' ')
       *np++ = *op;
} while (*op++);

printf("%s\n", newstr);

You can see why people invented other languages ;)你可以明白为什么人们发明了其他语言;)

if you are still interested, this function removes spaces from the beginning of the string, and I just had it working in my code:如果您仍然感兴趣,这个函数会从字符串的开头删除空格,我只是让它在我的代码中工作:

void removeSpaces(char *str1)  
{
    char *str2; 
    str2=str1;  
    while (*str2==' ') str2++;  
    if (str2!=str1) memmove(str1,str2,strlen(str2)+1);  
}
#include <ctype>

char * remove_spaces(char * source, char * target)
{
     while(*source++ && *target)
     {
        if (!isspace(*source)) 
             *target++ = *source;
     }
     return target;
}

Notes;笔记;

  • This doesn't handle Unicode.这不处理 Unicode。

The easiest and most efficient way to remove spaces from a string is to simply remove the spaces from the string literal.从字符串中删除空格的最简单最有效的方法是简单地从字符串文字中删除空格。 For example, use your editor to 'find and replace' "hello world" with "helloworld" , and presto!例如,使用您的编辑器将"hello world" “查找并替换"hello world""helloworld" ,然后就可以了!

Okay, I know that's not what you meant.好吧,我知道你不是这个意思。 Not all strings come from string literals, right?并非所有字符串都来自字符串文字,对吗? Supposing this string you want spaces removed from doesn't come from a string literal, we need to consider the source and destination of your string ... We need to consider your entire algorithm, what actual problem you're trying to solve, in order to suggest the simplest and most optimal methods.假设您想要从中删除空格的这个字符串不是来自字符串文字,我们需要考虑您的字符串的来源和目的地......我们需要考虑您的整个算法,您试图解决的实际问题,在为了建议最简单和最优化的方法。

Perhaps your string comes from a file (eg stdin ) and is bound to be written to another file (eg stdout ).也许您的字符串来自一个文件(例如stdin )并且必然会被写入另一个文件(例如stdout )。 If that's the case, I would question why it ever needs to become a string in the first place.如果是这样的话,我会质疑为什么它首先需要成为一个字符串。 Just treat it as though it's a stream of characters, discarding the spaces as you come across them...只要把它当作一个字符流,当你遇到它们时丢弃空格......

#include <stdio.h>

int main(void) {
    for (;;) {
        int c = getchar();
        if (c == EOF) { break;    }
        if (c == ' ') { continue; }
        putchar(c);
    }
}

By eliminating the need for storage of a string, not only does the entire program become much, much shorter, but theoretically also much more efficient.通过消除存储字符串的需要,整个程序不仅变得短,而且理论上也更高效。

#include<stdio.h>
#include<string.h>
main()
{
  int i=0,n;
  int j=0;
  char str[]="        Nar ayan singh              ";
  char *ptr,*ptr1;
  printf("sizeof str:%ld\n",strlen(str));
  while(str[i]==' ')
   {
     memcpy (str,str+1,strlen(str)+1);
   }
  printf("sizeof str:%ld\n",strlen(str));
  n=strlen(str);
  while(str[n]==' ' || str[n]=='\0')
    n--;
  str[n+1]='\0';
  printf("str:%s ",str);
  printf("sizeof str:%ld\n",strlen(str));
}

Code taken from zString library代码取自 zString 库

/* search for character 's' */
int zstring_search_chr(char *token,char s){
        if (!token || s=='\0')
        return 0;

    for (;*token; token++)
        if (*token == s)
            return 1;

    return 0;
}

char *zstring_remove_chr(char *str,const char *bad) {
    char *src = str , *dst = str;

    /* validate input */
    if (!(str && bad))
        return NULL;

    while(*src)
        if(zstring_search_chr(bad,*src))
            src++;
        else
            *dst++ = *src++;  /* assign first, then incement */

    *dst='\0';
    return str;
}

Code example代码示例

  Exmaple Usage
      char s[]="this is a trial string to test the function.";
      char *d=" .";
      printf("%s\n",zstring_remove_chr(s,d));

  Example Output
      thisisatrialstringtotestthefunction

Have a llok at the zString code, you may find it useful https://github.com/fnoyanisi/zString对 zString 代码有一个 llok,你可能会发现它很有用https://github.com/fnoyanisi/zString

That's the easiest I could think of (TESTED) and it works!!这是我能想到的最简单的(已测试)并且它有效!!

char message[50];
fgets(message, 50, stdin);
for( i = 0, j = 0; i < strlen(message); i++){
        message[i-j] = message[i];
        if(message[i] == ' ')
            j++;
}
message[i] = '\0';

Here is the simplest thing i could think of.这是我能想到的最简单的事情。 Note that this program uses second command line argument (argv[1]) as a line to delete whitespaces from.请注意,该程序使用第二个命令行参数(argv[1])作为删除空格的行。

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

/*The function itself with debug printing to help you trace through it.*/

char* trim(const char* str)
{
    char* res = malloc(sizeof(str) + 1);
    char* copy = malloc(sizeof(str) + 1);
    copy = strncpy(copy, str, strlen(str) + 1);
    int index = 0;

    for (int i = 0; i < strlen(copy) + 1; i++) {
        if (copy[i] != ' ')
        {
            res[index] = copy[i];
            index++;
        }
        printf("End of iteration %d\n", i);
        printf("Here is the initial line: %s\n", copy);
        printf("Here is the resulting line: %s\n", res);
        printf("\n");
    }
    return res;
}

int main(int argc, char* argv[])
{
    //trim function test

    const char* line = argv[1];
    printf("Here is the line: %s\n", line);

    char* res = malloc(sizeof(line) + 1);
    res = trim(line);

    printf("\nAnd here is the formatted line: %s\n", res);

    return 0;
}
/* Function to remove all spaces from a given string.
   https://www.geeksforgeeks.org/remove-spaces-from-a-given-string/
*/
void remove_spaces(char *str)
{
    int count = 0;
    for (int i = 0; str[i]; i++)
        if (str[i] != ' ')
            str[count++] = str[i];
    str[count] = '\0';
}

This is implemented in micro controller and it works, it should avoid all problems and it is not a smart way of doing it, but it will work :)这是在微控制器中实现的,它可以工作,它应该避免所有问题,这不是一个聪明的方法,但它会工作:)

void REMOVE_SYMBOL(char* string, uint8_t symbol)
{
  uint32_t size = LENGHT(string); // simple string length function, made my own, since original does not work with string of size 1
  uint32_t i = 0;
  uint32_t k = 0;
  uint32_t loop_protection = size*size; // never goes into loop that is unbrakable
  while(i<size)
  {
    if(string[i]==symbol)
    {
      k = i;
      while(k<size)
      {
        string[k]=string[k+1];
        k++;
      }
    }
    if(string[i]!=symbol)
    {
      i++;
    }
    loop_protection--;
    if(loop_protection==0)
    {
      i = size;
      break;
    }
  }
}

While this is not as concise as the other answers, it is very straightforward to understand for someone new to C, adapted from the Calculix source code.虽然这不像其他答案那么简洁,但对于 C 的新手来说,理解它是非常简单的,改编自 Calculix 源代码。

char* remove_spaces(char * buff, int len)
{
    int i=-1,k=0;
    while(1){
        i++;
        if((buff[i]=='\0')||(buff[i]=='\n')||(buff[i]=='\r')||(i==len)) break;
        if((buff[i]==' ')||(buff[i]=='\t')) continue;
        buff[k]=buff[i];
        k++;
    }
    buff[k]='\0';
    return buff;
}

I assume the C string is in a fixed memory, so if you replace spaces you have to shift all characters.我假设 C 字符串在固定内存中,因此如果替换空格,则必须移动所有字符。

The easiest seems to be to create new string and iterate over the original one and copy only non space characters.最简单的似乎是创建新字符串并迭代原始字符串并仅复制非空格字符。

I came across a variation to this question where you need to reduce multiply spaces into one space "represent" the spaces.我遇到了这个问题的一个变体,您需要将多个空格减少为一个“代表”空格的空格。

This is my solution:这是我的解决方案:

char str[] = "Put Your string Here.....";

int copyFrom = 0, copyTo = 0;

printf("Start String %s\n", str);

while (str[copyTo] != 0) {
    if (str[copyFrom] == ' ') {
        str[copyTo] = str[copyFrom];
        copyFrom++;
        copyTo++;

        while ((str[copyFrom] == ' ') && (str[copyFrom] !='\0')) {
            copyFrom++;
        }
    }

    str[copyTo] = str[copyFrom];

    if (str[copyTo] != '\0') {
        copyFrom++;
        copyTo++;
    }
}

printf("Final String %s\n", str);

Hope it helps :-)希望能帮助到你 :-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM