【问题标题】:Removing all spaces from a string [duplicate]从字符串中删除所有空格[重复]
【发布时间】:2013-09-06 12:36:25
【问题描述】:
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main()
{
  string str;
  cin>>str;
  str.erase(remove_if(str.begin(), str.end(), isspace),str.end());
  cout<<str;
  return 0;
}

错误信息:

/home/satish/Desktop/CPP/Remove_Spaces/main.cpp|9|错误:没有匹配函数调用'remove_if(std::basic_string::iterator, std::basic_string::iterator, )'|

【问题讨论】:

  • 除了 之外,您还需要使用 ::isspace 才能使用具有语言环境作为参数的 isspace 的 C 实现。
  • @Angew 谢谢!它工作得非常好。 :)

标签: c++ string


【解决方案1】:

首先,std::isspace&lt;cctype&gt; 中声明,所以包含它。

其次,您需要通过将函数强制转换为显式类型来消除重载的歧义:

str.erase(
    remove_if(str.begin(), str.end(), static_cast<int(*)(int)>(isspace)),
    str.end());

第三,正如詹姆斯所说,这会导致所有不在 ASCII 范围内的字符出现未定义的行为,并且由于您通常不能排除这一点,因此您需要努力确保只有正字符代码被传递给 @ 987654324@:

bool char_isspace(char c) {
    return std::isspace(static_cast<unsigned char>(c));
}

…

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

【讨论】:

  • 除了用char 调用这个版本的isspace 在大多数系统上是未定义的行为。
  • 因为标准 (C) 是这样说的。 “标题 声明了几个对字符分类和映射有用的函数 在所有情况下,参数都是一个 int,其值应表示为无符号字符或应等于宏 EOF。如果参数有任何其他值,则行为未定义。 (添加了重点。)普通的char 转换为int 时,将产生负值,不能表示为unsigned char
  • @James 那么你是说在 C 中调用 isspace('ß') 是未定义的,因为纯字符文字的类型为 int 并且可以签名?
  • 是的。当然,大多数情况下,您只会得到随机结果,因为isspace 的传统实现只是将参数用作表的索引(并且通常会映射表之前的内存)。我使用的至少一个实现(Sun C)实际上在其标签之前复制了表的一部分,因此负索引起作用了——除了isspace( 'ÿ' ),因为'ÿ' 的代码恰好是-1,与EOF相同。
  • @詹姆斯。谢谢你的信息,我不知道。我非常讨厌 C。
【解决方案2】:

如 cmets 中所述,您缺少 std::isspace 的包含,即 &lt;cctype&gt;。但即使那样你也不会成功,因为 isspace 已超载see here

重载问题的解决方案是将函数指针显式转换为所需的函数签名:

str.erase(remove_if(str.begin(), str.end(), static_cast<int(*)(int)>(&std::isspace)),str.end());

但是,正如 cmets 中所述,此处使用的 isspace 具有未定义的行为如果它获取非 ASCII 字符。在这种情况下,最好使用将语言环境作为第二个参数的模板版本:

C++14:

str.erase(
  remove_if(str.begin(), str.end(), 
    [](auto c){ return isspace(c, cin.getloc());}
  ),
str.end());

C++11: 同上,lambda 以 char c 作为参数(C++11 中没有多态 lambda)。

C++03 with boost:使用boost::bindremove_if创建谓词

str.erase(
  remove_if(str.begin(), str.end(), 
    boost::bind(&std::isspace<char>, _1, boost::ref(cin.getloc()))
  ),
str.end());

不带 boost 的 C++03: 将手写函子定义为谓词

struct IsSpace {
  bool operator()(char c) {
    return std::isspace(c, cin.getloc());
  }
};

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

【讨论】:

  • @KonradRudolph 是的。然而,接受的答案提到存在重载。更改了链接以引用该答案。
  • 抱歉,我仍然打开了指向 std::isspace 文档的链接,并错误地认为您已链接到该页面。
  • 与@KonradRudolph 的注释相同:您不能调用std::isspace 的版本,它接受一个带有char 的参数。这是未定义的行为。
  • @JamesKanze 仅当您传递非 ascii 字符时。但是,我更新了答案以考虑到这一点
  • @ArneMertz 他从某个地方得到了std::string。您如何确定其中没有负值。 (今天还有没有使用纯 ASCII 的系统。)
【解决方案3】:

试试这个方法:

#include <iostream>
#include <string>
#include <algorithm>

struct SpaceRemover
{
    bool operator( )( char _ch ) { return std::isspace( _ch ); }
};

int main( )
{
    std::string strSource = "   type    ddd     ";
    std::cout << "[main] Source string :\""<< strSource << "\"" << std::endl;

    std::string::iterator itEnd = std::remove_if( strSource.begin(), 
                                                  strSource.end(), 
                                                  SpaceRemover( ) );
    strSource.resize( std::distance( strSource.begin(), itEnd ) );

    std::cout << "[main] Result string :\""<< strSource << "\"" << std::endl;

    return 0;
}

【讨论】:

    【解决方案4】:
    #include <iostream>
    
    int main() {
        std::string original =  "   type    ddd     ";
        std::string result;
        for(char c: original) {
            if( ! std::isspace(c)) result += c;
        }
        original.swap(result);
        std::cout << "Modified: " << original << std::endl;
        return 0;
    }
    

    如果可以预测结果大小(或者只取原始大小就足够了),则 result.reserve() 将提高性能。

    【讨论】:

      【解决方案5】:

      由于到目前为止所有的答案都涉及未定义的行为......

      “最简单”的解决方案,如果你有 C++11 的话, 是:

      str.erase(
          std::remove_if(
              str.begin(),
              str.end(), 
              []( char ch ) { return isspace( static_cast<unsigned char>( ch ) ); } ),
          str.end() );
      

      没有unsigned char 的转换,isspace 的输入将 使函数的(未经检查的)先决条件失败很简单 char 已签名。

      如果你没有 C++11,或者你会需要这种 其他地方的东西(跳过空格等),你 可以写一个单独的谓词函数对象:

      struct IsSpace
      {
          bool operator()( char ch ) const
          {
              return isspace( static_cast<unsigned char>( ch ) );
          }
      };
      

      您可能还需要IsNotSpace 和相应的对象 &lt;ctype.h&gt; 中的其余 is... 函数。

      或者,您可以使用支持语言环境的版本 &lt;locale&gt;中的函数:

      template <std::ctype_base>::mask mask, bool is>
      class Is
      {
          std::locale m_toEnsureLifetime;
          std::ctype<char> const* m_ctype;
      public:
          Is( std::locale const& l = std::locale() )
              : m_toEnsureLifetime( l )
              , m_ctype( &std::use_facet<std::ctype<char>>( m_toEnsureLifetime ) )
          {
          }
          bool operator()( char ch ) const
          {
              return m_ctype->is( mask, ch ) == is;
          }
      };
      typedef Is<std::ctype_base::space, true> IsSpace;
      typedef Is<std::ctype_base::space, false> IsNotSpace;
      //  ...
      

      虽然有点复杂,但它完全支持语言环境,并且 实际上需要更少的代码(因为掩码可以是模板 论据)。

      【讨论】:

        猜你喜欢
        • 2014-04-01
        • 2014-08-26
        • 2019-11-25
        • 2019-01-09
        • 2013-12-11
        • 2011-08-24
        • 2023-04-08
        • 2013-04-14
        相关资源
        最近更新 更多