Удалить пробелы из std :: string в C ++


222

Каков предпочтительный способ удаления пробелов из строки в C ++? Я мог бы перебрать все символы и создать новую строку, но есть ли лучший способ?

Ответы:


257

Лучше всего использовать алгоритм remove_ifи isspace:

remove_if(str.begin(), str.end(), isspace);

Теперь сам алгоритм не может изменить контейнер (только изменить значения), поэтому он фактически перетасовывает значения вокруг и возвращает указатель на то, где должен быть конец. Поэтому мы должны вызвать string :: erase, чтобы фактически изменить длину контейнера:

str.erase(remove_if(str.begin(), str.end(), isspace), str.end());

Также следует отметить, что remove_if сделает максимум одну копию данных. Вот пример реализации:

template<typename T, typename P>
T remove_if(T beg, T end, P pred)
{
    T dest = beg;
    for (T itr = beg;itr != end; ++itr)
        if (!pred(*itr))
            *(dest++) = *itr;
    return dest;
}

54
Поскольку у «isspace» есть перегрузки, вам, вероятно, нужно будет квалифицировать общий код для использования :: isspace (реализация C, которая не принимает локаль) или встретить с загадочными ошибками создания шаблонов.
Bklyn

4
Все - с осторожностью относитесь к описанному выше методу (две отдельные строки, а не шаблонная версия, хотя она может иметь одну и ту же проблему). Я использовал это в проекте, не понимая, что это не всегда правильно. Например, если вы передаете ей строку «1 + 1», она возвращает «1 + 11». Я переключился на метод @rupello ниже, и он отлично работал в этом случае. Удачного кодирования!
JoeB

6
@Joe Ответ явно упоминает, что вам нужно позвонить eraseпозже. Это вернет правильный результат.
Конрад Рудольф

31
-1 это использование isspaceUB для всех наборов символов, кроме оригинального 7-битного ASCII. C99 §7.4 / 1. это не удивляет меня , что это было upvoted в размере 71 голосов , в настоящее время, несмотря на то , очень плохой совет.
ура и hth. - Альф

16
Повторим еще раз: код в этом ответе передает отрицательные значения (отличные от EOF) isspaceдля всех символов, не входящих в ASCII, с практическим выбором подписи по умолчанию для char. Таким образом, он имеет неопределенное поведение . Я повторяю это, потому что я подозреваю преднамеренную попытку заглушить этот факт в шуме.
ура и hth. - Альф

100
std::string::iterator end_pos = std::remove(str.begin(), str.end(), ' ');
str.erase(end_pos, str.end());

31
Мой голос за каноническое стирание / удаление идиомы. Может быть преобразован в один слой: str.erase (std :: remove (str.begin (), str.end (), ''), str.end ());
Bklyn

11
Примечание: вам нужно включить, <algorithm>чтобы это работало.
Тара

37

От gamedev

string.erase(std::remove_if(string.begin(), string.end(), std::isspace), string.end());

22
Это не будет компилироваться в реализациях, соответствующих стандартам, из-за перегрузок std :: isspace, принимающих локали. Вам нужно будет использовать :: isspace или выполнить некоторые нечитаемые махинации с помощью std :: bind2nd. Разве общий код не красив?
Bklyn

Также обратите внимание, что если какой-либо из символов является отрицательным (например, символ UTF8, когда символ подписан), используется значение ::isspaceUB.
Мартин Боннер поддерживает Монику

30

Можете ли вы использовать Boost String Algo? http://www.boost.org/doc/libs/1_35_0/doc/html/string_algo/usage.html#id1290573

erase_all(str, " "); 

3
Это медленнее, чем remove_if(str.begin(), str.end(), isspace);упоминал Мэтт Прайс. Я не знаю почему. На самом деле, все вспомогательные элементы, имеющие альтернативы STL, работают медленнее, чем соответствующие gcc (все, что я тестировал). Некоторые из них намного медленнее! (до 5 раз во вставках unordered_map) Возможно, это связано с кэшем ЦП общей среды или чем-то в этом роде.
Etherealone


15

Вы можете использовать это решение для удаления символа:

#include <algorithm>
#include <string>
using namespace std;

str.erase(remove(str.begin(), str.end(), char_to_remove), str.end());

1
#include <string.h> using пространство имен std;
slackmart

Это решение мне подходит. Верхний нет.
Джейсон Лю

1
следует избегать использования пространства имен std. stackoverflow.com/questions/1452721/…
infinitezero

12

Привет, ты можешь сделать что-то подобное. Эта функция удаляет все пробелы.

string delSpaces(string &str) 
{
   str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
   return str;
}

Я сделал еще одну функцию, которая удаляет все ненужные пробелы.

string delUnnecessary(string &str)
{
    int size = str.length();
    for(int j = 0; j<=size; j++)
    {
        for(int i = 0; i <=j; i++)
        {
            if(str[i] == ' ' && str[i+1] == ' ')
            {
                str.erase(str.begin() + i);
            }
            else if(str[0]== ' ')
            {
                str.erase(str.begin());
            }
            else if(str[i] == '\0' && str[i-1]== ' ')
            {
                str.erase(str.end() - 1);
            }
        }
    }
    return str;
}

8
string replaceinString(std::string str, std::string tofind, std::string toreplace)
{
        size_t position = 0;
        for ( position = str.find(tofind); position != std::string::npos; position = str.find(tofind,position) )
        {
                str.replace(position ,1, toreplace);
        }
        return(str);
}

используй это:

string replace = replaceinString(thisstring, " ", "%20");
string replace2 = replaceinString(thisstring, " ", "-");
string replace3 = replaceinString(thisstring, " ", "+");

7

Если вы хотите сделать это с помощью простого макроса, вот один:

#define REMOVE_SPACES(x) x.erase(std::remove(x.begin(), x.end(), ' '), x.end())

Это предполагает, что вы сделали, #include <string>конечно.

Назовите это так:

std::string sName = " Example Name ";
REMOVE_SPACES(sName);
printf("%s",sName.c_str()); // requires #include <stdio.h>

5
почему вы используете макрос для этого?
дани

1
Меньше ввода с клавиатуры для обычной задачи.
Volomike

3
Столь же коротким для call-сайта является вызов функции, принимающей lvalue-ссылку на строку. Макросы могут иметь удивительное поведение, взаимодействуя со своими аргументами (особенно с побочными эффектами), но, что еще хуже, если они вовлечены в ошибку, их имена не отображаются в сообщениях компилятора, их реализация делает.
Крис Уздавинис,

2

Я использовал описанную ниже работу надолго - не уверен насчет ее сложности.

s.erase(std::unique(s.begin(),s.end(),[](char s,char f){return (f==' '||s==' ');}),s.end());

когда вы хотите удалить персонажа ' 'и некоторые, например, - использовать

s.erase(std::unique(s.begin(),s.end(),[](char s,char f){return ((f==' '||s==' ')||(f=='-'||s=='-'));}),s.end());

аналогично просто увеличьте ||число символов, которое вы хотите удалить, не 1

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


1
string removeSpaces(string word) {
    string newWord;
    for (int i = 0; i < word.length(); i++) {
        if (word[i] != ' ') {
            newWord += word[i];
        }
    }

    return newWord;
}

Этот код в основном берет строку и проходит через все символы в ней. Затем он проверяет, является ли эта строка пробелом, если нет, то символ добавляется в новую строку.


1
   #include <algorithm>
   using namespace std;

   int main() {
       .
       .
       s.erase( remove( s.begin(), s.end(), ' ' ), s.end() );
       .
       .
   }

Источник:

Ссылка взята с этого форума.


1
Это на самом деле не добавляет ничего больше, чем этот ответ уже делает. Есть ли еще объяснение или детали, которые вы могли бы добавить, чтобы сделать ваш ответ более качественным и заслуживающим внимания по этому вопросу?
Das_Geek

Я думаю, что это проще , потому что он делает то же самое в одном утверждении.
Джон

2
Большой! Затем поместите это рассуждение как объяснение прямо в своем ответе . Первоначальному вопросу уже более одиннадцати лет , и без обоснования ваш ответ может быть воспринят как шум по сравнению с другими принятыми, хорошо оцененными ответами. Наличие этого объяснения поможет избежать удаления вашего ответа.
Das_Geek

Это было бы хорошо, но я не мог понять, как я должен вставить это в свой ответ ... что мой ответ лучше, чем этот ответ . ? Было бы очень приятно, если бы вы могли отредактировать мой ответ.
Джон

2
К сожалению, редактирование вашего ответа для добавления этого контента само по себе будет противоречить рекомендациям по редактированию , и мое редактирование, скорее всего, будет отклонено или отменено позже. Вы можете использовать первую ссылку в этом комментарии, чтобы редактировать ответ самостоятельно. Вполне допустимо заявить, что вы думаете, что ваш ответ лучше, чем какой-либо другой, и предоставить обоснование для него. Сообщество решит, правы вы или нет, путем голосования.
Das_Geek

0

В C ++ 20 вы можете использовать бесплатную функцию std :: erase

std::string str = " Hello World  !";
std::erase(str, ' ');

Полный пример:

#include<string>
#include<iostream>

int main() {
    std::string str = " Hello World  !";
    std::erase(str, ' ');
    std::cout << "|" << str <<"|";
}

Я печатаю | так что очевидно, что пространство в начале также удаляется.

примечание: при этом удаляется только пробел, а не все другие возможные символы, которые могут считаться пробелами, см. https://en.cppreference.com/w/cpp/string/byte/isspace


0

Удаляет все пробельные символы, такие как символы табуляции и переноса строк (C ++ 11):

string str = " \n AB cd \t efg\v\n";
str = regex_replace(str,regex("\\s"),"");

Почему вы рекомендуете этот подход в ответ на принятый ответ @ Matt-Price более десяти лет назад?
Джереми Кейни

Пусть все решения будут представлены здесь. Может кому-то понадобится это решение.
AnselmRu

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

1
Возможно, это решение не самое экономичное, но оно позволяет избавиться от всех пробельных символов «\ s», а не только от пробелов.
AnselmRu


-1
string removespace(string str)
{    
    int m = str.length();
    int i=0;
    while(i<m)
    {
        while(str[i] == 32)
        str.erase(i,1);
        i++;
    }    
}

3
Обычно желательно, чтобы вы добавили краткое объяснение к ответам на код.
arcyqwerty

1
@test - length()возвращает, а size_tне int. erase()Посмотри, а size_typeне int. Функция, вероятно, завершится ошибкой, если встретятся два последовательных пробела, поскольку индекс всегда увеличивается. Если удаляется один пробел, цикл будет читать за пределами строки. Вы, вероятно, должны удалить этот ответ, так как он нуждается в большой помощи.
jww

-3

Боюсь, это лучшее решение, которое я могу придумать. Но вы можете использовать reserve () для предварительного выделения минимально необходимой памяти заранее, чтобы немного ускорить процесс. В итоге вы получите новую строку, которая, вероятно, будет короче, но она займет тот же объем памяти, но вы избежите перераспределения.

РЕДАКТИРОВАТЬ: В зависимости от вашей ситуации, это может потребовать меньше накладных расходов, чем жонглирование символов вокруг.

Вам следует попробовать разные подходы и посмотреть, что лучше для вас: у вас могут вообще не быть проблем с производительностью.


remove_if создает не более одной копии каждого значения. Так что на самом деле не так много накладных расходов относительно того, что нужно сделать.
Мэтт Прайс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.