Удаление пробелов из строки в C? - PullRequest
42 голосов
/ 13 ноября 2009

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

Ответы [ 13 ]

72 голосов
/ 13 ноября 2009

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

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

void RemoveSpaces(char* source)
{
  char* i = source;
  char* j = source;
  while(*j != 0)
  {
    *i = *j++;
    if(*i != ' ')
      i++;
  }
  *i = 0;
}
16 голосов
/ 13 ноября 2009

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

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

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

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

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

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

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

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

10 голосов
/ 21 мая 2015

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

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

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

7 голосов
/ 13 ноября 2009

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

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

2 голосов
/ 21 мая 2015

Самый простой и самый эффективный способ удалить пробелы из строки - это просто удалить пробелы из строкового литерала. Например, используйте ваш редактор, чтобы «найти и заменить» "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 голосов
/ 23 июня 2013

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

void removeSpaces(char *str1)  
{
    char *str2; 
    str2=str1;  
    while (*str2==' ') str2++;  
    if (str2!=str1) memmove(str1,str2,strlen(str2)+1);  
}
2 голосов
/ 13 ноября 2009
#include <ctype>

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

Примечание;

  • Это не обрабатывает Unicode.
1 голос
/ 03 апреля 2014
#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));
}
0 голосов
/ 20 февраля 2019
void spaces_be_gone(char *str)
{
    char *p = --str;
    do while (*++p == ' ');
    while (*++str = *p);
}
0 голосов
/ 08 апреля 2017

Я наткнулся на вариант этого вопроса, в котором вам нужно уменьшить количество пробелов в одном, чтобы «представить» пробелы.

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

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

Надеюсь, это поможет: -)

...