Удаление пробелов из строки в C?

каков самый простой и эффективный способ удаления пробелов из строки в C?

12 ответов


самый простой и эффективный обычно не идут вместе...

вот возможное решение (непроверено):

void RemoveSpaces(char* source)
{
  char* i = source;
  char* j = source;
  while(*j != 0)
  {
    *i = *j++;
    if(*i != ' ')
      i++;
  }
  *i = 0;
}

вот очень компактная, но совершенно правильная версия:

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

и здесь, просто для моего развлечения, есть версии с кодовым гольфом, которые не совсем корректны и расстраивают комментаторов.

Если вы можете рисковать неопределенным поведением и никогда не иметь пустых строк, вы можете избавиться от тела:

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

Черт, если под пробелом вы подразумеваете только пробел:

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

не используйте это в производстве:)


как мы можем видеть из ответов, опубликованных, это удивительно не тривиальная задача. Столкнувшись с подобной задачей, многие программисты предпочитают выбросить здравый смысл из окна, чтобы создать самый неясный фрагмент, который они могут придумать.

вещи для рассмотрения:

  • вы хотите сделать копию строки с удаленными пробелами. Изменение переданной строки-плохая практика, это может быть строковый литерал. Кроме того, есть иногда преимущества обработки строк как неизменяемые объекты.
  • нельзя предположить, что исходная строка не пуста. Он может содержать только один символ окончания null.
  • буфер назначения может содержать любой неинициализированный мусор при вызове функции. Проверка его на нулевое завершение не имеет никакого смысла.
  • исходный код документации должно быть указано, что буфер должен быть достаточно большим, чтобы содержать обрезанная веревка. Самый простой способ сделать это-сделать его таким же большим, как необрезанная строка.
  • буфер назначения должен содержать строку с нулевым завершением без пробелов, когда функция выполнена.
  • подумайте, хотите ли вы удалить все символы пробела или просто пробелы ' '.
  • программирование на С-это не соревнование за то, кто может втиснуть как можно больше операторов на одной линии. Это скорее наоборот, хорошая программа C содержит читаемый код (всегда одно-самое важное качество) без ущерба для эффективности программы (несколько важно).
  • по этой причине вы не получаете бонусных очков за скрытие вставки нулевого завершения строки назначения, позволяя ей быть частью кода копирования. Вместо этого сделайте вставку null termination явной, чтобы показать, что вам не просто удалось получить ее случайно.

что бы я сделал:

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

В этом коде исходная строка "str_untrimmed" остается нетронутой, что гарантируется правильной корректностью const. Он не аварийно завершается, если исходная строка содержит только нулевое завершение. Он всегда null завершает строку назначения.

выделение памяти остается вызывающему абоненту. Алгоритм должен сосредоточиться только на своей работе. Он удаляет все пробелы.

в коде нет тонких трюков. Он не пытается втиснуть как можно больше операторов на одной линии. Это будет очень плохой кандидат на IOCCC. Тем не менее, он даст почти тот же машинный код, что и более неясные однострочные версии.

при копировании чего-то вы можете немного оптимизировать, объявив оба указателя как restrict, который является контрактом между программистом и компилятором, где программист гарантирует, что назначение и источник не являются одним и тем же адресом (или, скорее, что данные, на которые они указывают, доступны только через это указатель, а не через какой-то другой указатель). Это позволяет более эффективно оптимизировать, так как компилятор может копировать прямо из источника в место назначения без временной памяти между ними.


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

вы можете видеть, почему люди изобрели другие языки ;)


#include <ctype>

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

заметки;

  • это не обрабатывает Unicode.

Если вы все еще заинтересованы, эта функция удаляет пробелы из начала строки, и я только что работал в своем коде:

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

проще и самый эффективный способ удалить пробелы из строки-просто удалить пробелы из строкового литерала. Например, используйте редактор, чтобы "найти и заменить""hello world" С "helloworld" и вуаля!


#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]=='')
    n--;
  str[n+1]='';
  printf("str:%s ",str);
  printf("sizeof str:%ld\n",strlen(str));
}

Я предполагаю, что строка C находится в фиксированной памяти, поэтому, если вы заменяете пробелы, вам нужно переместить все символы.

самым простым, по-видимому, является создание новой строки и итерация по исходной и копирование только не пробелов.


Это самое простое, что я мог придумать (протестировано), и это работает!!

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] = '';

код взят из библиотеки zString

/* search for character 's' */
int zstring_search_chr(char *token,char s){
        if (!token || s=='')
        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='';
    return str;
}

пример кода

  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

имейте llok в коде zString, вы можете найти его полезным https://github.com/fnoyanisi/zString


я наткнулся на вариант этого вопроса, где вам нужно уменьшить многократные пространства в одно пространство, "представляющее" пространства.

Это мое решение:

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] !='')) {
            copyFrom++;
        }
    }

    str[copyTo] = str[copyFrom];

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

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

надеюсь, что это помогает :-)