移除std::string中的空格

22
在C++中,将以下内容转换为一个简单的方法:
这个std::string
\t\tHELLO WORLD\r\nHELLO\t\nWORLD     \t

转化为:

HELLOWORLDHELLOWORLD

1
@tomislav-maric 我认为这不是那篇帖子的重复,那里的OP正在使用cin流,因此使用iostream函数。 - Mr. Smith
相似但不完全重复,因此不投票关闭。 - CashCow
@CashCow 我再次检查了一遍...你是正确的,对此我很抱歉。 - tmaric
6个回答

35

std::remove_ifstd::string::erase简单组合。

不是完全安全的版本。

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

为了更安全的版本,请将::isspace替换为

std::bind( std::isspace<char>, _1, std::locale::classic() )

(包括所有相关的标题)

如果要使用替代字符类型的版本,请将<char>替换为<ElementType>或您的模板字符类型。当然,您也可以用不同的语言环境来替换。如果这样做,请注意避免重新创建语言环境因素导致的低效率。

在C++11中,您可以使用以下lambda函数将更安全的版本转换为:

[]( char ch ) { return std::isspace<char>( ch, std::locale::classic() ); }

4
除了基本字符集以外的所有字符,isspace函数都具有未定义行为。此规定来自于 C99 标准第7.4/1节。 - R. Martinho Fernandes
2
C++98将C标准库的行为委托给了C89,而C++11则将C标准库的行为委托给了C99。 - R. Martinho Fernandes
1
抱歉,我对问题的真正本质有些混淆 :) 我知道使用 isspace 是错误的,但我搞混了为什么会这样。这是因为 isspace 取一个 int,而 char 是有符号的。这里有一个解释该问题的小程序 http://stacked-crooked.com/view?id=817f92f4a2482e5da0b7533285e53edb。 - R. Martinho Fernandes
1
请注意,这与多字节编码无关;源代码中任何值大于0x7F的字节,无论编码方式如何,都会触发此问题;即使是像Latin-1或Windows-1252这样的单字节编码也会导致此问题。只有7位编码,如ASCII,才能正常工作。 - R. Martinho Fernandes
Lambda版本不需要“return”语句吗? - PatchyFog
显示剩余13条评论

13

如果是C++03

struct RemoveDelimiter
{
  bool operator()(char c)
  {
    return (c =='\r' || c =='\t' || c == ' ' || c == '\n');
  }
};

std::string s("\t\tHELLO WORLD\r\nHELLO\t\nWORLD     \t");
s.erase( std::remove_if( s.begin(), s.end(), RemoveDelimiter()), s.end());

或使用 C++11 lambda 表达式

s.erase(std::remove_if( s.begin(), s.end(), 
     [](char c){ return (c =='\r' || c =='\t' || c == ' ' || c == '\n');}), s.end() );

PS. 擦除删除成语 被使用了


4

c++11

std::string input = "\t\tHELLO WORLD\r\nHELLO\t\nWORLD     \t";

auto rs = std::regex_replace(input,std::regex("\\s+"), "");

std::cout << rs << std::endl;

/tmp ❮❮❮ ./play /tmp目录下运行play文件
HELLOWORLDHELLOWORLD

4

在C++11中,您可以使用lambda而不是使用std::bind:

str.erase(
    std::remove_if(str.begin(), str.end(), 
        [](char c) -> bool
        { 
            return std::isspace<char>(c, std::locale::classic()); 
        }), 
    str.end());

3

您可以使用 Boost.Algorithmerase_all

#include <boost/algorithm/string/erase.hpp>
#include <iostream>
#include <string>

int main()
{
    std::string s = "Hello World!";
    // or the more expensive one-liner in case your string is const
    // std::cout << boost::algorithm::erase_all_copy(s, " ") << "\n";
    boost::algorithm::erase_all(s, " "); 
    std::cout << s << "\n";
}

注意:正如评论中所提到的:trim_copy(或其类似函数 trim_copy_lefttrim_copy_right)仅会从字符串开头和结尾删除空格。


我看到一些使用Boost的解决方案,但我不是在寻找一个“trim”函数,我相信修剪是做类似于XX___XX_-> XX_XX这样的事情,而我想要最终的解决方案是XXXX - Mr. Smith

2

逐个字符地分析并使用 string::erase() 应该可以很好地解决问题。

void removeWhitespace(std::string& str) {
    for (size_t i = 0; i < str.length(); i++) {
        if (str[i] == ' ' || str[i] == '\n' || str[i] == '\t') {
            str.erase(i, 1);
            i--;
        }
    }
}

1
当相邻的空格字符存在时,代码无法正常工作。第一个空格被删除,第二个空格下移至位置i。然后继续循环,增加i,但不会检查第二个空格。 - Steve Jessop
你说得对。已经修复了。 - SelectricSimian

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