269

What is the preferred way to remove spaces from a string in C++? I could loop through all the characters and build a new string, but is there a better way?

Steve Hanov
  • 11,316
  • 16
  • 62
  • 69

19 Answers19

304

The best thing to do is to use the algorithm remove_if and isspace:

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

Now the algorithm itself can't change the container(only modify the values), so it actually shuffles the values around and returns a pointer to where the end now should be. So we have to call string::erase to actually modify the length of the container:

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

We should also note that remove_if will make at most one copy of the data. Here is a sample implementation:

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;
}
Matt Price
  • 43,887
  • 9
  • 38
  • 44
  • 65
    Because 'isspace' has overloads, you will probably need to qualify the generic code to use ::isspace (the C implementation that doesn't take a locale) or be greeted with cryptic template instantiation errors. – Bklyn Jan 05 '09 at 15:10
  • 4
    All - be wary of the above method (The two single lines, not the templated version, although it may have the same issue). I used it in a project without realizing that it isn't always correct. For example, if you pass it the string "1 + 1" it returns "1+11". I switched to @rupello 's method below and it worked fine for this case. Happy coding! – JoeB Apr 19 '12 at 18:43
  • 7
    @Joe The answer explicitly mentions that you need to call `erase` afterwards. That will return the correct result. – Konrad Rudolph Sep 15 '12 at 07:17
  • 40
    -1 this use of `isspace` is UB for all character sets except original 7-bit ASCII. C99 §7.4/1. it *does not surprise* me that it's been upvoted to the tune of 71 votes by now, in spite of being Very Bad Advice. – Cheers and hth. - Alf Oct 25 '12 at 13:48
  • I don't know why but remove_if wrks incorrect in OS X – fnc12 Aug 03 '14 at 08:52
  • 1
    @Cheersandhth.-Alf: c99 `isspace()` accepts any `int` value representable as `unsigned char` (+EOF). I don't see UB for `std::string`. What am I missing here? – jfs Sep 10 '14 at 18:26
  • 2
    @J.F.Sebastian: you're simply missing that with most every (if not just "every") extant C++ compiler, `char` is by default a *signed integer* type. Thus for non-ASCII characters you get negative values. E.g., with Latin-1 and the default signedness choice, Norwegian characters ÆØÅ and æøå are negative. – Cheers and hth. - Alf Sep 10 '14 at 20:48
  • 1
    @Cheersandhth.-Alf: No information is lost: `char -> int`. All `signed char` are "representable" as `unsigned char`. [`::isspace()` returns the same result with gcc, clang -std=c++11](https://gist.github.com/zed/ba2de81701a187cbbd83). Are you saying that "most every" C++ compiler doesn't include gcc, clang? Or they doesn't follow the standard on some other (not mine) system? – jfs Sep 10 '14 at 21:26
  • 3
    @J.F.Sebastian: when you pass a negative value except EOF, to `isspace`, you have Undefined Behavior. because the C++ standard says so, by way of incorporating the C standard. it's as simple as that. you might relate that back to your argument (which has a different conclusion) to identify the flaw or flaws. anyway the code in this answer passes negative values for all non-ASCII characters, with the default signedness of `char`. Thus it has **Undefined Behavior**, which *can* have the effect that you naïvely and incorrectly expect. That's basic knowledge. – Cheers and hth. - Alf Sep 10 '14 at 21:37
  • 2
    To try it out you can experiment with different character classification functions in debug builds with Visual C++. Some of the implementations are table-driven and will crash on non-EOF negative arguments. That's what having UB means: that in some cases, with some compilers or context, you get some other behavior than what you naïvely and incorrectly expect, i.e. non-portable code. – Cheers and hth. - Alf Sep 10 '14 at 21:49
  • 1
    @Cheersandhth.-Alf: *"because the C++ standard says so"* -- where does it say it? We already established that `C99 §7.4/1` doesn't say it unless you claim that `char` is not representable as `unsigned char`. I've tested that both gcc and clang produce the expected result (`isspace()` has the same value for `char` and `unsigned char`) on my machine. Does [the code](https://gist.github.com/zed/ba2de81701a187cbbd83) fail on Visual C++? Also, Microsoft is a "standard" but it is not C++11 standard. – jfs Sep 10 '14 at 21:57
  • 2
    @J.F.Sebastian: about half of the `signed char` values are not representable as `unsigned char` in the meaning of representable employed by the standard. the same terminology is used for conversion from unsigned to signed, where "otherwise, the value is implementation-defined" (C++11 §4.7/3). thus you are effectively claiming that the word representable, used about the same thing, means two entirely different things in two different parts of the standard. if so then that's a hitherto unknown defect in the standard. you should report it. – Cheers and hth. - Alf Sep 10 '14 at 22:03
  • 24
    Just to repeat, the code in this answer passes negative values (different from EOF) to `isspace`, for all non-ASCII characters, with the in-practice default choice of signedness for `char`. Thus it has **undefined behavior**. I'm repeating it because I suspect a deliberate attempt to drown that fact in noise. – Cheers and hth. - Alf Sep 10 '14 at 22:07
  • 2
    @Cheersandhth.-Alf: you are right. +1. It is **undefined behavior** to pass a negative `int` that is not `EOF` to `isspace()` in C11. It took me asking the question [what does “representable” mean in C11?](http://stackoverflow.com/q/25776824/4279) to understand. "Never attribute to malice that which is adequately explained by stupidity" :) – jfs Sep 11 '14 at 03:31
  • Not only that, I think that MSVC actually asserts on this fact mean that your program _will_ crash if you do this for some input. – Emil Eriksson May 25 '15 at 17:55
  • 2
    `error: no matching function for call to ‘remove_if(std::__cxx11::basic_string::iterator, std::__cxx11::basic_string::iterator, )’` – ar2015 Mar 16 '17 at 07:18
  • 2
    `No matching function for call to 'remove_if'` even included the algorithm library. – Jason Liu Oct 15 '17 at 23:22
  • Will this be quicker than regex_replace(inputString,"\\s+", "")? – Ram Kishore Jun 20 '19 at 14:01
  • 1
    Gee imagine if C++ supported str.replace(" ", ""); How life would be much simpler! – user997112 Oct 22 '20 at 14:09
  • For those who don't want to remove new lines but only tabs and spaces a simpler function `::isblank` would work well. Note: It would still have the unsigned char UB though. – Angaj Sharma Sep 09 '22 at 08:28
134
std::string::iterator end_pos = std::remove(str.begin(), str.end(), ' ');
str.erase(end_pos, str.end());
Arno
  • 2,169
  • 1
  • 15
  • 12
  • 41
    My up-vote for the canonical erase/remove idiom. Can be made into a one liner: str.erase (std::remove (str.begin(), str.end(), ' '), str.end()); – Bklyn Jan 05 '09 at 15:08
  • 18
    Note: You need to include `` for this to work. – Tara Jul 13 '16 at 01:36
43

From gamedev

string.erase(std::remove_if(string.begin(), string.end(), std::isspace), string.end());
Anthony
  • 12,177
  • 9
  • 69
  • 105
rupello
  • 8,361
  • 2
  • 37
  • 34
  • 25
    This will not compile on standards-conforming implementations because of the locale-taking overloads of std::isspace. You'll need to use ::isspace or perform some unreadable machinations with std::bind2nd. Isn't generic code beautiful? – Bklyn Jan 05 '09 at 15:23
  • 1
    Also note that if any of the characters is negative (eg a UTF8 char when char is signed), use of `::isspace` is UB. – Martin Bonner supports Monica Dec 02 '19 at 08:38
  • 5
    C++17 solution: `string.erase(std::remove_if(string.begin(), string.end(), [](unsigned char x) { return std::isspace(x); }), string.end());` – Michal Steller Apr 12 '21 at 16:44
34

Can you use Boost String Algo? http://www.boost.org/doc/libs/1_35_0/doc/html/string_algo/usage.html#id1290573

erase_all(str, " "); 
Nemanja Trifunovic
  • 24,346
  • 3
  • 50
  • 88
  • 4
    It is slower than the `remove_if(str.begin(), str.end(), isspace);` that Matt Price mentioned. I don't know why. Actually, all the boost stuff, that have STL alternatives, are slower than the corresponding gcc ones (All the ones I tested). Some of them are immensely slower! (up to 5 times in unordered_map inserts) Maybe it is because of the CPU cache of the shared environment or something like it. – Etherealone Aug 14 '12 at 20:23
23

You can use this solution for removing a char:

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

str.erase(remove(str.begin(), str.end(), char_to_remove), str.end());
Jason Liu
  • 749
  • 4
  • 16
  • 34
user2281802
  • 231
  • 2
  • 2
18

For trimming, use boost string algorithms:

#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;

// ...

string str1(" hello world! ");
trim(str1);      // str1 == "hello world!"
Christian
  • 1,017
  • 3
  • 14
  • 30
Roman
  • 221
  • 2
  • 2
12

Hi, you can do something like that. This function deletes all spaces.

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

I made another function, that deletes all unnecessary spaces.

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;
}
Vinayak Garg
  • 6,518
  • 10
  • 53
  • 80
ddacot
  • 1,212
  • 3
  • 14
  • 40
9

If you want to do this with an easy macro, here's one:

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

This assumes you have done #include <string> of course.

Call it like so:

std::string sName = " Example Name ";
REMOVE_SPACES(sName);
printf("%s",sName.c_str()); // requires #include <stdio.h>
dimitar.bogdanov
  • 387
  • 2
  • 10
Volomike
  • 23,743
  • 21
  • 113
  • 209
  • 9
    why would you use a macro for this? – dani Jan 15 '17 at 12:53
  • 1
    Less keyboard typing for a common task. – Volomike Jan 15 '17 at 13:23
  • 8
    Equally short for the call-site is calling a _function_ taking a lvalue-reference to a string. Macros can have surprising behaviors interacting with their arguments (esp with side effects), but worse, if they're involved in an error, their names do not show up in compiler messages, their implementation does. – Chris Uzdavinis Apr 29 '19 at 04:23
  • 1
    Yes - macros can make debugging and maintenance very difficult. In a small program, maybe they're OK. In a multi-million line application with hundreds of projects, macros can really be a pain. – GTAE86 Oct 01 '20 at 16:21
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);
}

use it:

string replace = replaceinString(thisstring, " ", "%20");
string replace2 = replaceinString(thisstring, " ", "-");
string replace3 = replaceinString(thisstring, " ", "+");
SudoBash
  • 91
  • 1
  • 2
8

In C++20 you can use free function std::erase

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

Full example:

#include<string>
#include<iostream>

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

I print | so that it is obvious that space at the begining is also removed.

note: this removes only the space, not every other possible character that may be considered whitespace, see https://en.cppreference.com/w/cpp/string/byte/isspace

NoSenseEtAl
  • 28,205
  • 28
  • 128
  • 277
4
   #include <algorithm>
   using namespace std;

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

Source:

Reference taken from this forum.

Deepanshu
  • 141
  • 1
  • 5
  • 1
    This doesn't really add anything more than [this answer](https://stackoverflow.com/a/83481/11384392) already does. Is there more explanation or detail you could add to make your answer higher quality and worth keeping on this question? – Das_Geek Nov 26 '19 at 14:45
  • I think it's more _simpler_, 'cause it does the same thing in one statement. – Deepanshu Nov 26 '19 at 15:27
  • 2
    Great! Then put that reasoning as an explanation *directly in your answer*. The original question is more than *eleven years old*, and without a justification your answer could get seen as noise when compared to the other accepted, well-upvoted answers. Having that explanation will help keep your answer from being removed. – Das_Geek Nov 26 '19 at 15:31
  • That would be _good_ but I couldn't get that how should I put _that_ into my answer... _that my answer is better than [this answer](https://stackoverflow.com/a/83481/11384392)._? It would be a great pleasure if you could _edit_ my answer. – Deepanshu Nov 26 '19 at 15:40
  • 2
    Unfortunately, [editing your answer](https://stackoverflow.com/posts/59053051/edit) to add that content myself would go against the [editing guidelines](https://stackoverflow.com/help/privileges/edit), and my edit would likely get declined or rolled back later. You can use the first link in this comment to edit the answer yourself. It's totally acceptable to state that you think your answer is better than some other one, and provide justification for it. The community will decide whether you're right by upvoting or downvoting. – Das_Geek Nov 26 '19 at 15:44
  • _Thanks_ @Das_Geek – Deepanshu Nov 26 '19 at 15:46
  • Please someone explain how the above line remove the spaces.What is the execution flow.?? – Chandra Shekhar Feb 29 '20 at 15:48
4

Removes all whitespace characters such as tabs and line breaks (C++11):

string str = " \n AB cd \t efg\v\n";
str = regex_replace(str,regex("\\s"),"");
AnselmRu
  • 51
  • 2
  • Why would you recommend this approach over @Matt-Price‘s accepted answer from over a decade ago? – Jeremy Caney Jun 05 '20 at 04:27
  • Let all solutions be presented here. Maybe someone will need this solution. – AnselmRu Jun 05 '20 at 04:47
  • I’m not arguing against that. I’m saying make it easier for people to assess different approaches by explaining the differences and what scenarios they might be better suited for. – Jeremy Caney Jun 05 '20 at 05:20
  • 3
    Probably this solution is not the most economical, but it allows you to get rid of all [whitespace characters](https://en.wikipedia.org/wiki/Category:Whitespace) '\s', not just spaces ' '. – AnselmRu Jun 05 '20 at 05:34
2

I used the below work around for long - not sure about its complexity.

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

when you wanna remove character ' ' and some for example - use

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

likewise just increase the || if number of characters you wanna remove is not 1

but as mentioned by others the erase remove idiom also seems fine.

RaGa__M
  • 2,550
  • 1
  • 23
  • 44
2
string removeSpaces(string word) {
    string newWord;
    for (int i = 0; i < word.length(); i++) {
        if (word[i] != ' ') {
            newWord += word[i];
        }
    }

    return newWord;
}

This code basically takes a string and iterates through every character in it. It then checks whether that string is a white space, if it isn't then the character is added to a new string.

Crisp Apples
  • 267
  • 1
  • 2
  • 13
1

Just for fun, as other answers are much better than this.

#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");
}
Enlico
  • 23,259
  • 6
  • 48
  • 102
0

I created a function, that removes the white spaces from the either ends of string. Such as " Hello World ", will be converted into "Hello world".

This works similar to strip, lstrip and rstrip functions, which are frequently used in 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;
}
D...
  • 57
  • 8
-1
string removespace(string str)
{    
    int m = str.length();
    int i=0;
    while(i<m)
    {
        while(str[i] == 32)
        str.erase(i,1);
        i++;
    }    
}
jww
  • 97,681
  • 90
  • 411
  • 885
test c
  • 9
  • 1
  • 4
    It is generally preferred that you add a brief explanation to code answers. – arcyqwerty May 04 '15 at 19:39
  • 1
    @test - `length()` returns a `size_t`, not an `int`. `erase()` takes a `size_type`, not an `int`. The function will probably fail if two consecutive spaces are encountered since the index is always incremented. If one space is removed, then the loop will read beyond the string's bounds. You should probably delete this answer since it needs a lot of help. – jww May 04 '15 at 19:52
-1
  string str = "2C F4 32 3C B9 DE";
  str.erase(remove(str.begin(),str.end(),' '),str.end());
  cout << str << endl;

output: 2CF4323CB9DE

kfc
  • 567
  • 1
  • 5
  • 10
-3

I'm afraid it's the best solution that I can think of. But you can use reserve() to pre-allocate the minimum required memory in advance to speed up things a bit. You'll end up with a new string that will probably be shorter but that takes up the same amount of memory, but you'll avoid reallocations.

EDIT: Depending on your situation, this may incur less overhead than jumbling characters around.

You should try different approaches and see what is best for you: you might not have any performance issues at all.

jww
  • 97,681
  • 90
  • 411
  • 885
Dave Van den Eynde
  • 17,020
  • 7
  • 59
  • 90
  • remove_if makes at most one copy of each value. So there really isn't that much overhead relative to what needs to be done. – Matt Price Sep 17 '08 at 14:04