Видаліть пробіли з std :: string в C ++


222

Який бажаний спосіб видалити пробіли з рядка в C ++? Я міг би проглянути всі символи та створити нову рядок, але чи є кращий спосіб?

Відповіді:


257

Найкраще робити алгоритм remove_ifта простір:

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 це використання isspaceє UB для всіх наборів символів, крім оригінальних 7-бітових ASCII. C99 §7.4 / 1. це не дивує мене , що це було upvoted в розмірі 71 голосів , в даний час, не дивлячись на те , дуже погана порада.
Ура та хт. - Альф

16
На повторення, код у цій відповіді передає негативні значення (відмінні від EOF) isspaceдля всіх символів, що не належать до ASCII, з практичним вибором підпису за замовчуванням char. Таким чином, він має невизначену поведінку . Я повторюю це, бо підозрюю навмисну ​​спробу заглушити цей факт у шумі.
Ура та хт. - Альф

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

Від гамедева

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

22
Це не буде компілюватися у відповідності зі стандартами реалізацій через локальні перевантаження std :: isspace. Вам потрібно буде використовувати :: isspace або здійснити кілька нечитабельних обробок за допомогою std :: bind2nd. Хіба загальний код не прекрасний?
Bklyn

Також зауважте, що якщо будь-який із символів є негативним (наприклад, знак UTF8 під час підписання char), то використовується ::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 разів у невпорядкованих_мапах) Можливо, це через кеш процесора спільного середовища або щось подібне.
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> з використанням простору імен std;
млявий

Це рішення для мене правильне. Верхній - ні.
Джейсон Лю

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
чому б ви використовували для цього макрос?
dani

1
Менше набору клавіатури для звичайного завдання.
Воломіке

3
Не менш коротким для сайту виклику є виклик функції, що приймає посилання 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()повертає a size_t, а не an int. erase()бере, а size_typeне ан int. Функція, ймовірно, не зможе, якщо зустрічаються два послідовних пробіли, оскільки індекс завжди збільшується. Якщо один пробіл буде видалено, цикл буде читати за межі рядка. Ви, ймовірно, повинні видалити цю відповідь, оскільки їй потрібна велика допомога.
jww

-3

Боюся, це найкраще рішення, про яке я можу придумати. Але ви можете скористатися резервом (), щоб заздалегідь виділити мінімум необхідної пам'яті, щоб трохи прискорити роботу. Ви отримаєте новий рядок, який, ймовірно, буде коротшим, але він займе стільки ж пам’яті, але ви уникнете перерозподілу.

EDIT: Залежно від вашої ситуації, це може спричинити менше накладних витрат, ніж поєднання символів навколо.

Спробуйте скористатися різними підходами і побачити, що найкраще підходить для вас: у вас взагалі не виникне проблем із продуктивністю.


Remove_if робить щонайбільше одну копію кожного значення. Тож насправді не так багато накладних витрат щодо того, що потрібно зробити.
Метт Ціна
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.