web-dev-qa-db-ja.com

Cの文字列からスペースを削除しますか?

Cの文字列からスペースを削除する最も簡単で効率的な方法は何ですか?

44
Tyler Treat

最も簡単で最も効率的なのは、通常一緒に行かないことです...

考えられる解決策は次のとおりです。

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

これは非常にコンパクトですが、完全に正しいバージョンです。

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

そして、ここでは、私の娯楽のために、完全に正しいわけではなく、コメンターを怒らせるコードゴルフバージョンがあります。

いくつかの未定義の動作を危険にさらすことができ、空の文字列を持たない場合は、本文を削除できます。

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

ちなみに、スペースで言うと、単にスペース文字を意味する場合:

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

本番環境では使用しないでください:)

16
Kornel

投稿された回答からわかるように、これは驚くほど簡単な作業ではありません。このようなタスクに直面したとき、多くのプログラマーは、思い付く可能性のある最もあいまいなスニペットを作成するために、常識を窓から外すことを選択しているように思われます。

考慮事項:

  • スペースを削除して、文字列のコピーを作成します。渡された文字列を変更するのは悪い習慣で、文字列リテラルの場合があります。また、文字列を 不変オブジェクト として扱う利点もあります。
  • ソース文字列が空ではないと仮定することはできません。単一のヌル終了文字のみを含めることができます。
  • 宛先バッファには、関数が呼び出されたときに初期化されていないガベージを含めることができます。 null終了を確認しても意味がありません。
  • ソースコードのドキュメントには、トリミングされた文字列を格納するのに十分な大きさの宛先バッファが必要であると記載する必要があります。これを行う最も簡単な方法は、トリミングされていない文字列と同じ大きさにすることです。
  • 宛先バッファは、関数の実行時に空白なしのヌル終了文字列を保持する必要があります。
  • すべての空白文字を削除するか、スペースだけを削除するかを検討してください' '
  • Cプログラミングは、1行にできるだけ多くの演算子を絞り込める競合相手ではありません。むしろ逆です。優れたCプログラムには、プログラムの効率(やや重要)を犠牲にすることなく、読み取り可能なコード(常に最も重要な品質)が含まれています。
  • このため、コピー先の文字列のヌル終端の挿入を隠し、コピーコードの一部にすることでボーナスポイントを獲得することはできません。代わりに、null終端の挿入を明示的に行って、偶然にそれを正しく取得できなかったことを示します。

私がすること:

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

このコードでは、ソース文字列「str_untrimmed」はそのまま残ります。これは、適切なconstの正確性を使用することで保証されます。ソース文字列にnull終了のみが含まれている場合、クラッシュしません。宛先文字列は常にnullで終了します。

メモリの割り当ては呼び出し元に任されています。アルゴリズムは、意図された作業を行うことにのみ焦点を当てるべきです。すべての空白が削除されます。

コードには微妙なトリックはありません。 1行で可能な限り多くの演算子を絞り込もうとはしません。 [〜#〜] ioccc [〜#〜] の非常に貧弱な候補になります。それでも、より曖昧なワンライナーバージョンとほぼ同じマシンコードが生成されます。

ただし、何かをコピーするときは、両方のポインターをrestrictとして宣言することでビットを最適化できます。これは、プログラマーとコンパイラーの間の契約です。 、彼らが指しているデータは、そのポインタを介してのみアクセスされ、他のポインタを介してはアクセスされない)。これにより、コンパイラは一時メモリなしでソースから宛先に直接コピーできるため、より効率的な最適化が可能になります。

11
Lundin

Cでは、一部の文字列をインプレースで置き換えることができます。たとえば、strdup()によって返される文字列です。

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

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

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

コード内で宣言された文字列など、他の文字列は読み取り専用です。これらを新しく割り当てられたメモリ領域にコピーし、スペースをスキップしてコピーを埋める必要があります。

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);

人々が他の言語を発明した理由を見ることができます;)

7
Andomar

文字列からスペースを削除する最も簡単なand最も効率的な方法は、単に文字列リテラルからスペースを削除することです。たとえば、エディタを使用して「検索して置換」_"hello world" with "helloworld"、およびプレスト!

わかりました、それはあなたが意図したものではないことを知っています。すべての文字列が文字列リテラルに由来するわけではありませんか?スペースを削除したいこの文字列が文字列リテラルに由来しないと仮定すると、string...のソースと宛先を考慮する必要があります...アルゴリズム全体を考慮する必要があります、最も簡単で最適な方法を提案するために、解決しようとしている実際の問題。

おそらく、あなたの文字列はファイル(例:stdin)から来ており、別のファイル(例:stdout)に書き込まれるようにバインドされています。その場合、最初に文字列をにする必要がある理由を疑問に思うでしょう。それが文字の流れであるかのように扱うだけで、あなたがそれらに遭遇したときにスペースを捨てます...

#include <stdio.h>

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

文字列を保存する必要をなくすことで、プログラム全体が大幅にmuch短くなるだけでなく、理論的にははるかに効率的になります。

2
autistic

まだ興味がある場合は、この関数は文字列の先頭からスペースを削除し、コードで機能させただけです。

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

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

ノート;

  • これはUnicodeを処理しません。
2
quark
#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));
}
1
Narayan Singh

それは私が考えることができる最も簡単な(テスト済み)であり、動作します!!

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';
0
nAiN

C文字列は固定メモリにあるため、スペースを置き換える場合はすべての文字をシフトする必要があります。

最も簡単なのは、新しい文字列を作成して元の文字列を反復処理し、スペース以外の文字のみをコピーすることです。

0
stefanB