【问题标题】:remove whitespace in std::string [duplicate]删除 std::string 中的空格 [重复]
【发布时间】:2012-12-23 08:57:19
【问题描述】:

在C++中,有什么简单的转法:

这个 std::string

\t\tHELLO WORLD\r\nHELLO\t\nWORLD     \t

进入:

HELLOWORLDHELLOWORLD

【问题讨论】:

  • @tomislav-maric 我不认为这是该帖子的副本,那里的 OP 正在使用 cin 流,因此使用 iostream 函数。
  • 相似但不完全重复,因此不投票结束。
  • @CashCow 我再次检查了它。你是对的,对此感到抱歉。

标签: c++ string c++11 removing-whitespace


【解决方案1】:

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() )

(包括所有相关的标题)

对于使用替代字符类型的版本,将 &lt;char&gt; 替换为 &lt;ElementType&gt; 或任何您的模板字符类型。当然,您也可以将语言环境替换为不同的语言环境。如果您这样做,请注意避免多次重新创建语言环境方面的低效率。

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

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

【讨论】:

  • @chris ::isspace 也包括新行:cplusplus.com/reference/cctype/isspace
  • isspace 对所有字符都有 UB,除了基本的东西。 C99 §7.4/1。
  • C++98 将 C 标准库的行为委托给 C89,C++11 将 C 标准库的行为委托给 C99。
  • 我很抱歉。我对问题的真正性质有点困惑 :) 我知道使用 isspace 是错误的,但我对原因感到困惑。原因与isspace 接受intchar 被签名有关。这是一个解释问题的小程序stacked-crooked.com/view?id=817f92f4a2482e5da0b7533285e53edb
  • (请注意这与多字节编码无关;源中任何值高于 0x7F 的字节,无论编码如何都会触发此问题;即使是单字节编码像 Latin-1 或 Windows-1252 会导致它。只有像 ASCII 这样的 7 位编码可以正常工作)
【解决方案2】:

你可以使用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";
}

注意:正如 cmets 中所述:trim_copy(或其表亲 trim_copy_lefttrim_copy_right)仅删除字符串开头和结尾的空格。

【讨论】:

  • 我看到了一些使用 Boost 的解决方案,但我不是在使用 trim 函数,修剪我相信正在做类似XX___XX_ -> XX_XX 而我想要的最终解决方案成为XXXX
【解决方案3】:

如果 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。使用Erase-remove idiom

【讨论】:

    【解决方案4】:

    一个字符一个字符地遍历它并使用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--;
            }
        }
    }
    

    【讨论】:

    • 当有相邻的空格字符时不起作用。第一个被擦除,将第二个向下移动到位置i。然后你绕过循环,增加i,并且永远不要检查第二个。
    • 你是对的。修好了。
    【解决方案5】:

    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

    HELLOWORLDHELLOWORLD
    

    【讨论】:

      【解决方案6】:

      在 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());
      

      【讨论】:

        猜你喜欢
        • 2018-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-27
        • 1970-01-01
        • 1970-01-01
        • 2023-02-24
        • 2022-10-24
        相关资源
        最近更新 更多