【问题标题】:Parse string of integers into std vector? [duplicate]将整数字符串解析为标准向量? [复制]
【发布时间】:2011-12-09 20:23:09
【问题描述】:

可能重复:
Parsing a comma-delimited std::string

我想把一个字符串解析成一个整数向量:

string s = "1;2;4;8;16;";
vector<int> n = parse_string(s);
// n == [1, 2, 4, 8, 16];

当然,我可以用strtokatoi 编写一个简单的代码。但是,使用 C++ boost 的代码会更短吗?我从未尝试过使用 Boost,但听说它可以像使用 Python 一样简单地编写代码。

【问题讨论】:

标签: c++ string boost


【解决方案1】:

不用Boost也可以做到:

string s = "1;2;4;8;16";
vector<int> n;
transform(s.begin(), s.end(), [](char c){return c == ';' ? ' ' : c});
stringstream ss(s);
copy(istream_iterator<int>(ss), istream_iterator<int>(), back_inserter(n));

编辑: 如果您只想使用 C++03 代码,您必须编写:

char semicolon_to_space(char c){
  return c == ';' ? ' ' : c
};

// ...

string s = "1;2;4;8;16";
vector<int> n;
transform(s.begin(), s.end(), semicolon_to_space);
stringstream ss(s);
copy(istream_iterator<int>(ss), istream_iterator<int>(), back_inserter(n))

【讨论】:

  • 需要注意的是这段代码是C++11
  • 它可以很容易地重写为 C++03。你只需要将 lambda 作为外部命名函数踢出。
  • 循环替换';' with ' ' 有点浪费。您可以通过将转换器对象添加到 istream_iterator 来在单个操作中完成此操作,如下所示。
  • 在纯 C++03(或 C++11)中,您也可以在第一步中使用std::replacestd::replace( s.begin(), s.end(), ';', ' ' );,这也比 lambda 或外部函数更具可读性。
  • 首先,为此您必须获取非常量字符串或将其复制
【解决方案2】:

我不是boost profi,所以我的代码并不理想:

#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/foreach.hpp>
#include <iostream>
#include <vector>
#include <string>

int main() 
{
    using namespace boost::algorithm;

    std::vector< std::string > result;
    split(result, "1;2;4;8;16;", is_any_of(";"));

    BOOST_FOREACH(const std::string& item, result)
    {
        std::cout << item << std::endl;
    }
}

你肯定可以处理 is_any_of

【讨论】:

  • split 在命名空间boost,而不是boost::algorithm
  • 在文件中 (boost/algorithm/string/split.hpp) 它在 boost::algorithm 中
  • 我明白了。显然,两者都有。
【解决方案3】:

我认为在这种情况下应该使用两种不同的算法。第一个将是一个解析器,它将分离您的值 boost::split http://www.boost.org/doc/libs/1_48_0/doc/html/string_algo/reference.html#header.boost.algorithm.string.split_hpp 应该会有所帮助。第二个是词法转换,它将你的字符串整数转换为 int 值,看看 boost::lexical_cast.

【讨论】:

    【解决方案4】:

    boost::tokenizer?想知道我是否遗漏了一些东西,但这不是该应用程序的理想选择吗?

    http://www.boost.org/doc/libs/1_43_0/libs/tokenizer/char_separator.htm 上的示例

    【讨论】:

      【解决方案5】:

      如果它们是空格分隔的更容易:
      如果这是一个很容易添加的要求。

      #include <vector>
      #include <iterator>
      #include <algorithm>
      
      int main()
      {
          string s = "1 2 4 8 16";
          std::stringstream s_stream(s);
      
          vector<int> n;
          std::copy(std::istream_iterator<int>(s_stream), std::istream_iterator<int>(),
                    std::back_inserter(n)
                   );
      }
      

      如果你必须有';'然后可以插入一个简单的转换器类。

      struct IntReader
      {
          int value;
          operator int() {return value;}
          friend std::istream& operator>>(std::istream& stream, IntReader& data)
          {
              char x = 0;
              if ((stream >> data.value >> x) && (x != ';'))
              {   stream.setstate(std::ios::failbit);
              }
              return stream;
          }
      };
      

      然后只需更改副本以使用它:

          std::copy(std::istream_iterator<IntReader>(s_stream), std::istream_iterator<IntReader>(),
                    std::back_inserter(n)
                   );
      

      【讨论】:

      • 我已经添加了x变量的初始化,希望你不要介意。此外,我不确定operator&gt;&gt; 的实现。如果(stream &gt;&gt; data.value &gt;&gt;x),则stream 不应该设置failbit。也许条件应该被否定?
      • @DavidRodríguez-dribeas:我不认为 x 的初始化是必要的。在stream &gt;&gt; data.value &gt;&gt; x 中,如果任何部分发生故障,那么故障位已经设置,我不需要做任何事情。如果它有效,那么我们需要检查 x 的值。但由于它工作了,我们知道它已经被初始化,因此对x != ';' 的检查是有效的。因此,如果读取有效并且 x 不是 ';'然后我们设置失败位。
      • 然后if 读取:如果我们正确读取了数字和另一个不是; 的字符,则清除故障位?如果我们已经正确阅读(条件的前半部分是必需的,那么failbit 没有设置,因此if 的主体是无用的,对吧?我的问题是我不理解意图,应该是setstate 而不是 clear如果我们读取数字和字符,但字符不是 ;,那么出现问题了吗?
      • 应该设置failbbit。我的大脑显然没有工作。谢谢。
      猜你喜欢
      • 1970-01-01
      • 2021-04-23
      • 1970-01-01
      • 2021-11-03
      • 2014-01-06
      • 2010-10-03
      • 1970-01-01
      相关资源
      最近更新 更多