在C++中从std::string中删除空格

270

在C++中,去除字符串中的空格,最好的方法是什么?我可以循环遍历所有字符并构建一个新字符串,但是否有更好的方法?

19个回答

307

最好的方法是使用算法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;
}

66
由于'isspace'有多个重载,您可能需要限定使用::isspace(不带区域设置的C实现)来使用通用代码,否则会出现神秘的模板实例化错误。 - Bklyn
4
大家要注意上面的方法(两行单独的代码,不是模板版本,即使它可能具有相同的问题)。我在一个项目中使用它时没有意识到它并不总是正确的。例如,如果你传递给它字符串 "1 + 1",它会返回 "1+11"。我改用下面 @rupello 的方法,并且对于这种情况它运作得很好。祝编程愉快! - JoeB
7
答案明确提到您需要在调用erase之后。这将返回正确的结果。 - Konrad Rudolph
40
除了原始的7位ASCII字符集外,使用isspace的此用法对于所有字符集来说都是未定义行为。根据C99标准第7.4/1节。尽管这是非常糟糕的建议,但我并不感到惊讶它已经获得了71票的支持。 - Cheers and hth. - Alf
24
再次强调,这个答案中的代码会将负值(与EOF不同)传递给isspace函数,对于所有非ASCII字符,默认情况下使用char的有符号性。因此,它具有未定义行为。我再次重申这一点,因为我怀疑有人故意试图淹没这个事实。 - Cheers and hth. - Alf
显示剩余15条评论

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

41
我赞同使用经典的删除/擦除惯用语,并且可以将它转换成一行代码:str.erase(std::remove(str.begin(), str.end(), ' '), str.end())。 - Bklyn
18
请确保在代码中添加<algorithm>库以使其正常运行。 - Tara

43

来自gamedev

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

25
这段代码在符合标准的实现上无法编译,因为std::isspace有针对locale的重载。你需要使用::isspace或者进行一些难以理解的std::bind2nd操作。泛型代码真美妙啊! - Bklyn
1
还要注意,如果任何字符为负数(例如当char为有符号时的UTF8字符),使用::isspace是未定义行为。 - Martin Bonner supports Monica
5
C++17解法:string.erase(std::remove_if(string.begin(), string.end(), [](unsigned char x) { return std::isspace(x); }), string.end());简化翻译:这是使用C++17的一种解法,用于删除字符串中的空格。它使用了一个叫做std::remove_if的函数,将满足特定条件(即判断字符是否为空格)的字符移动到字符串的末尾,并返回一个指向新末尾后面位置的迭代器。最后,通过调用string.erase函数将这些字符从字符串中删除。 - Michal Steller

34

4
它比Matt Price提到的remove_if(str.begin(),str.end(),isspace)慢,但我不知道为什么。 实际上,所有有STL替代品的boost东西都比相应的gcc版本慢(我测试过的全部)。其中一些慢得惊人!(unordered_map插入速度最多慢了5倍) 可能是因为共享环境的CPU缓存或类似的原因。 - Etherealone

23
您可以使用此解决方案来删除一个字符:
#include <algorithm>
#include <string>
using namespace std;

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

1
#include <string.h> using namespace std; - slackmart
这个解决方案对我来说是正确的。排名第一的那个不是。 - Jason Liu
5
应避免使用 "using namespace std"。https://dev59.com/D3M_5IYBdhLWcg3wQQ3w - infinitezero

18

要进行字符串的修剪,请使用boost string algorithms

#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;

// ...

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

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

9

如果您想通过简单的宏来完成此操作,这里有一个:

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

9
为什么要使用宏来做这件事? - dani
1
常见任务键盘输入更少。 - Volomike
8
同样适用于调用使用左值引用字符串的 函数 的调用点。宏与其参数交互时可能会产生意想不到的行为(特别是带有副作用的宏),但更糟糕的是,如果它们涉及错误,则它们的名称不会出现在编译器消息中,而是它们的实现。 - Chris Uzdavinis
1
是的 - 宏可以使调试和维护变得非常困难。在小程序中,也许它们还行。但在数百个项目的多百万行应用程序中,宏确实可能会成为一个问题。 - GTAE86

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

8
在 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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接