it-roy-ru.com

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

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

41
Tyler Treat

Легче и эффективнее обычно не идти вместе ...

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

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

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

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

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

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

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

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

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

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

17
Kornel

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

Что нужно учитывать:

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

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

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» остается нетронутой, что гарантируется использованием правильной константной корректности. Не происходит сбой, если исходная строка не содержит ничего, кроме нулевого завершения. Это всегда нуль заканчивает строку назначения.

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

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

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

10
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

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

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

Возможно, ваша строка происходит из файла (например, stdin) и обязательно должна быть записана в другой файл (например, stdout). Если это так, я бы задал вопрос, зачем вообще нужно становиться строкой. Просто относитесь к нему, как к потоку символов, отбрасывая пробелы, когда вы сталкиваетесь с ними ...

#include <stdio.h>

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

Устраняя необходимость хранения строки, вся программа не только становится намного, намного короче, но теоретически также намного более эффективной.

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

Эффективное и довольно простое решение:

//Removespaces.
void be_gone_spaces(char *str)
{
    char *p = str;
    do *(*p == ' ' ? str : str++) = *p;
    while (*p++);
}
0
Tomer Wolberg

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

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

0
stefanB