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


222

在C ++中从字符串中删除空格的首选方法是什么?我可以遍历所有字符并构建新的字符串,但是有更好的方法吗?

Answers:


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 2012年

6
@Joe答案明确提到您需要erase事后致电。那将返回正确的结果。
康拉德·鲁道夫2012年

31
-1 isspace对于所有字符集(原始7位ASCII除外)的使用都是UB。C99§7.4/ 1。尽管这是非常不好的建议,但到目前为止,它已经获得71票赞成,这并不令感到惊讶
干杯和健康。-阿尔夫

16
只是重复一遍,isspace对于所有非ASCII字符,此答案中的代码将负值(与EOF不同)传递给,且在实践中默认选择的有符号性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

来自gamedev

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

22
由于std :: isspace的区域设置采用重载,因此无法在符合标准的实现中进行编译。您将需要使用:: isspace或对std :: bind2nd进行一些难以理解的修改。通用代码不漂亮吗?
Bklyn

还要注意,如果任何字符为负(例如,对char进行签名时为UTF8 char),则使用::isspaceis为UB。
马丁·邦纳

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);Matt Price提到的要慢。我不知道为什么 实际上,所有具有STL替代选择的boost东西都比相应的gcc(我测试过的所有东西)要慢。其中一些速度非常慢!(在unordered_map中最多插入5次)可能是由于共享环境的CPU缓存或类似原因。
Etherealone

16

要进行修剪,请使用升压字符串算法

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

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
常见任务的键盘输入更少。
Volomike

3
同样,调用站点的简称是调用一个对字符串进行左值引用的函数。宏与参数交互时会具有令人惊讶的行为(特别是带有副作用),但是更糟的是,如果它们涉及错误,它们的名称就不会出现在编译器消息中,而它们的实现会出现。
克里斯·乌兹达维尼斯

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
大!然后直接在您的答案中使用该推理作为解释。最初的问题已有11年以上的历史了,如果没有理由,您的回答与其他公认的,被好评的回答相比可能会被认为是很不合理。有了该解释将有助于防止您的答案被删除。
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

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

输出:2CF4323CB9DE


-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 2015年

1
@test- length()返回一个size_t,而不是interase()需要一个size_type,而不是一个int。如果遇到两个连续的空格,则该函数可能会失败,因为索引总是递增的。如果删除一个空格,则循环将读取超出字符串范围的内容。您可能应该删除此答案,因为它需要很多帮助。
jww 2015年

-3

恐怕这是我能想到的最佳解决方案。但是您可以使用reserve()预先预先分配所需的最小内存,以加快处理速度。您将得到一个可能更短的新字符串,但它占用的内存量相同,但是您将避免重新分配。

编辑:根据您的情况,这可能比使周围的字符散布花费更少的开销。

您应该尝试不同的方法,然后查看最适合您的方法:您可能根本没有任何性能问题。


remove_if每个值最多复制一份。因此,相对于需要完成的工作,实际上并没有那么多开销。
马特·普赖斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.