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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
229
0
390 106
19
Перейти к ответу Данный вопрос помечен как решенный

Ответы 19

От разработка игр

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

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

Bklyn 05.01.2009 18:23

Также обратите внимание, что если какой-либо из символов отрицательный (например, символ UTF8, когда char подписан), использование ::isspace - это UB.

Martin Bonner supports Monica 02.12.2019 11:38

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

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

Bklyn 05.01.2009 18:08

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

Tara 13.07.2016 04:36

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

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

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

remove_if создает не более одной копии каждого значения. Так что накладных расходов на то, что нужно сделать, действительно не так уж и много.

Matt Price 17.09.2008 18:04
Ответ принят как подходящий

Лучше всего использовать алгоритм 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;
}

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

Bklyn 05.01.2009 18:10

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

JoeB 19.04.2012 22:43

@Joe В ответе прямо упоминается, что вам нужно вызвать erase после этого. Это вернет правильный результат.

Konrad Rudolph 15.09.2012 11:17

-1 это использование isspace - это UB для всех наборов символов, кроме исходного 7-битного ASCII. C99 §7.4 / 1. Это не удивляет мне, что к настоящему моменту за него проголосовали 71 голос, несмотря на то, что он является очень плохим советом.

Cheers and hth. - Alf 25.10.2012 17:48

Я не знаю почему, но remove_if работает неправильно в OS X

fnc12 03.08.2014 12:52

@ Cheersandhth.-Alf: c99 isspace() принимает любое значение int, представленное как unsigned char (+ EOF). Не вижу UB для std::string. Что мне здесь не хватает?

jfs 10.09.2014 22:26

@ J.F.Sebastian: вам просто не хватает того, что для большинства (если не только «всех») существующих компиляторов C++ char по умолчанию является типом целое число со знаком. Таким образом, для символов, отличных от ASCII, вы получаете отрицательные значения. Например, с Latin-1 и выбором подписи по умолчанию норвежские символы ÆØÅ и æøå являются отрицательными.

Cheers and hth. - Alf 11.09.2014 00:48

@ Cheersandhth.-Альф: Информация не потеряна: char -> int. Все signed char "могут быть представлены" как unsigned char. ::isspace() возвращает тот же результат с gcc, clang -std = C++ 11. Вы хотите сказать, что «почти все» компиляторы C++ не включают gcc, clang? Или они не следуют стандарту какой-то другой (не моей) системы?

jfs 11.09.2014 01:26

@ J.F.Sebastian: когда вы передаете отрицательное значение, кроме EOF, в isspace, вы получаете Undefined Behavior. потому что стандарт C++ говорит об этом путем включения стандарта C. это так просто. вы можете связать это со своим аргументом (который имеет другой вывод), чтобы выявить изъян или изъяны. в любом случае код в этом ответе передает отрицательные значения для всех символов, отличных от ASCII, с подписью по умолчанию char. Таким образом, у него есть Неопределенное поведение, который может имеет эффект, которого вы наивно и неправильно ожидаете. Это базовые знания.

Cheers and hth. - Alf 11.09.2014 01:37

Чтобы попробовать это, вы можете поэкспериментировать с различными функциями классификации символов в отладочных сборках с помощью Visual C++. Некоторые из реализаций управляются таблицами и будут давать сбой при использовании отрицательных аргументов, отличных от EOF. Вот что означает наличие UB: в некоторых случаях с некоторыми компиляторами или контекстом вы получаете другое поведение, отличное от того, что вы наивно и неправильно ожидаете, то есть непереносимый код.

Cheers and hth. - Alf 11.09.2014 01:49

@ Cheersandhth.-Альф: "потому что стандарт C++ так говорит" - где это написано? Мы уже установили, что C99 §7.4/1 не говорит этого, если вы не утверждаете, что char не может быть представлен как unsigned char. Я проверил, что и gcc, и clang дают ожидаемый результат (isspace() имеет одинаковое значение для char и unsigned char) на моей машине. Не работает ли код в Visual C++? Кроме того, Microsoft является «стандартом», но не стандартом C++ 11.

jfs 11.09.2014 01:57

@ J.F.Sebastian: около половины значений signed char не могут быть представлены как unsigned char в значении представимых значений, используемом в стандарте. та же терминология используется для преобразования из беззнакового в подписанный, где «в противном случае значение определяется реализацией» (C++ 11 §4.7 / 3). таким образом, вы фактически утверждаете, что слово «представимый», используемое в отношении одного и того же, означает две совершенно разные вещи в двух разных частях стандарта. если так, то это неизвестный до сих пор дефект в стандарте. вы должны сообщить об этом.

Cheers and hth. - Alf 11.09.2014 02:03

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

Cheers and hth. - Alf 11.09.2014 02:07

@ Cheersandhth.-Альф: ты прав. +1. Это неопределенное поведение, чтобы передать отрицательный int, который не является EOF, в isspace() в C11. Мне потребовалось задать вопрос что означает «представимый» в C11?, чтобы понять. «Никогда не приписывайте злому умыслу то, что адекватно объясняется глупостью» :)

jfs 11.09.2014 07:31

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

Emil Eriksson 25.05.2015 20:55

error: no matching function for call to ‘remove_if (std::__cxx11::basic_string<char>::iterator, std::__cxx11::basic_string<char>::iterator, <unresolved overloaded function type>)’

ar2015 16.03.2017 10:18

No matching function for call to 'remove_if' даже включал библиотеку алгоритмов.

Jason Liu 16.10.2017 02:22

Будет ли это быстрее, чем regex_replace (inputString, "\\ s +", "")?

Ram Kishore 20.06.2019 17:01

Представьте, поддерживает ли C++ str.replace ("", ""); Как бы жизнь была намного проще!

user997112 22.10.2020 17:09

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

erase_all(str, " "); 

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

Etherealone 15.08.2012 00:23

Для обрезки используйте алгоритмы ускорения строки:

#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;

// ...

string str1(" hello world! ");
trim(str1);      // str1 == "hello world!"

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

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

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, " ", "+");

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

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

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

#include <string.h> с использованием пространства имен std;

slackmart 22.05.2013 03:50

Это решение мне подходит. Верхний - нет.

Jason Liu 16.10.2017 02:24

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

infinitezero 11.04.2018 11:54

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

Обычно рекомендуется добавлять краткое пояснение к ответам кода.

arcyqwerty 04.05.2015 22:39

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

jww 04.05.2015 22:52

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

#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>

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

dani 15.01.2017 15:53

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

Volomike 15.01.2017 16:23

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

Chris Uzdavinis 29.04.2019 07:23

Да - макросы могут очень затруднить отладку и обслуживание. В небольшой программе, может быть, они в порядке. В многомиллионном приложении с сотнями проектов макросы действительно могут стать проблемой.

GTAE86 01.10.2020 19:21

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

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

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

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

    return newWord;
}

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

   #include <algorithm>
   using namespace std;

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

Источник:

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

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

Das_Geek 26.11.2019 17:45

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

John 26.11.2019 18:27

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

Das_Geek 26.11.2019 18:31

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

John 26.11.2019 18:40

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

Das_Geek 26.11.2019 18:44
Спасибо @Das_Geek
John 26.11.2019 18:46

Пожалуйста, объясните, как в приведенной выше строке удаляются пробелы. Каков процесс выполнения. ??

Chandra Shekhar 29.02.2020 18:48

В 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

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

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

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

Jeremy Caney 05.06.2020 07:27

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

AnselmRu 05.06.2020 07:47

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

Jeremy Caney 05.06.2020 08:20

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

AnselmRu 05.06.2020 08:34

  string str = "2C F4 32 3C B9 DE";
  str.erase(remove(str.begin(),str.end(),' '),str.end());
  cout << str << endl;

вывод: 2CF4323CB9DE

Просто для удовольствия, так как другие ответы намного лучше, чем этот.

#include <boost/hana/functional/partial.hpp>
#include <iostream>
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/filter.hpp>
int main() {
    using ranges::to;
    using ranges::views::filter;
    using boost::hana::partial;
    auto const& not_space = partial(std::not_equal_to<>{}, ' ');
    auto const& to_string = to<std::string>;

    std::string input = "2C F4 32 3C B9 DE";
    std::string output = input | filter(not_space) | to_string;
    assert(output == "2CF4323CB9DE");
}

Я создал функцию, которая удаляет пробелы с обоих концов строки. Такие как " Hello World " будет преобразован в "Hello world".

Это работает аналогично функциям strip, lstrip и rstrip, которые часто используются в Python.

string strip(string str) {
    while (str[str.length() - 1] == ' ') {
        str = str.substr(0, str.length() - 1);
    }
    while (str[0] == ' ') {
        str = str.substr(1, str.length() - 1);
    }
    return str;
}

string lstrip(string str) {
    while (str[0] == ' ') {
        str = str.substr(1, str.length() - 1);
    }
    return str;
}

string rstrip(string str) {
    while (str[str.length() - 1] == ' ') {
        str = str.substr(0, str.length() - 1);
    }
    return str;
}

Другие вопросы по теме