简体   繁体   English

将字符串向量加入std :: ostream(如boost :: join)

[英]Join vector of strings to std::ostream (like boost::join)

I have a vector of strings and I want output it to stream (file stream, actually). 我有一个字符串向量,我想将它输出到流(文件流,实际上)。 And I want to have a delimiter between vector elements. 我希望在矢量元素之间有一个分隔符。 There is a way to use standard ostream_iterator 有一种方法可以使用标准的ostream_iterator

std::vector <std::string> strs;
std::ostream_iterator<std::string> out_file_iterator ( out_file, delim );
std::copy ( strs.begin(), strs.end(), out_file_iterator );

I didn't like this way because there is a delim text after each element, but I don't need to have a delim after last element. 我不喜欢这种方式,因为每个元素后面都有一个delim文本,但是我不需要在最后一个元素后面有一个delim I'd like to use something like boost::join . 我想使用像boost::join这样的东西。 However boost::join returns string and my vector too large to output it to string. 但是boost::join返回字符串,而我的向量太大而无法输出到字符串。

What is most elegant way to achieve my goal? 实现目标的最优雅方式是什么?

One way that works is to handle the last one separately. 一种方法是分别处理最后一个。 But don't think it's very elegant . 但不要以为它非常优雅 Of course, you could wrap the ugliness in your own join function. 当然,你可以在你自己的join函数中包含丑陋。

assert(strs.size() > 0);
std::ostream_iterator<std::string> out_file_iterator ( out_file, delim );
std::copy ( strs.begin(), strs.end()-1, out_file_iterator );
out_file << strs.back();

The most elegant would be to write your own loop. 最优雅的是编写自己的循环。 Or a seperate function. 或者单独的功能。

template<class Stream, class InIt>
void print_range(Stream& s, InIt first, InIt last, char const* delim = "\n"){
  if(first == last)
    return;
  s << *first++;
  for(; first != last; ++first){
    s << delim << *first;
  }
}

For a general solution (untested): 对于一般解决方案(未经测试):

template<class T>
class ostream_join_iterator {
public:

    // Construct like an ostream_iterator.
    ostream_join_iterator(std::ostream& stream,
        const std::string& delimiter = "")
        : stream(stream), delimiter(delimiter), first(true) {}

    // Behave like an output iterator.
    ostream_join_iterator& operator++()    { return *this; }
    ostream_join_iterator& operator++(int) { return *this; }
    ostream_join_iterator& operator*()     { return *this; }

    // Output a delimiter before all but the first element.
    template<class T>
    ostream_join_iterator& operator=(const T& value) {
        if (!first) {
            stream << delimiter;
        } else {
            first = false;
        }
        stream << value;
        return *this;
    }

private:

    std::ostream& stream;
    const std::string delimiter;
    bool first;

};

You can use it like a regular std::ostream_iterator : 您可以像常规std::ostream_iterator一样使用它:

std::copy(strings.begin(), strings.end(),
    ostream_join_iterator<std::string>(file, delimiter));

This is an idea with a functor 这是一个带有仿函数的想法

using namespace std;

struct add_delim_t {
  add_delim_t(const char *_delim) : delim_(_delim), is_first_(true) {}
  string operator () (const string &_val) {
    if (is_first_) { is_first_ = false; return _val; } else return delim_ + _val;
  }
private:
  const string delim_;
  bool is_first_;
};

transform(s.begin(), s.end(), ostream_iterator<string>(cout), add_delim_t(" , "));

The problem with this solution that it uses statefull predicate. 这个解决方案的问题在于它使用了statefull谓词。 Theoretically it means UB. 从理论上讲,它意味着UB。

There is an idea with Boost Function Input Iterator Boost函数输入迭代器有一个想法

using namespace std;

struct generator {
  typedef string result_type;
  generator(result_type _delim) : delim_(_delim), is_first_(true) {}
  result_type operator () () { 
    if (!is_first_)
      return delim_; 
    is_first_ = false; 
    return ""; 
  }
private:
  result_type delim_;
  bool is_first_;
};

template<class T>
struct reverse_plus : public binary_function<T, T, T> {
  T operator()(const T& _lhs, const T& _rhs) const { return (_rhs + _lhs); }
};

// output to file stream
transform
( strs.begin()
, strs.end()
, boost::make_function_input_iterator(generator(" , "), boost::infinite())
, ostream_iterator<string> out_file_iterator(out_file)
, reverse_plus<string>()
);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用boost :: algorithm :: join与对象的std :: vector? - How to use boost::algorithm::join with std::vector of objects? 通过boost :: algorithm :: join和boost :: adaptors :: transformed转换boost.asio :: ip :: address的std :: vector - Transform a std::vector of boost.asio::ip::address via boost::algorithm::join and boost::adaptors::transformed 用于std :: vector的Typedef和ostream运算符 - Typedef and ostream operator for a std::vector 用boost :: algorithms :: join提取和连接字符串 - Extracting and joining strings with boost::algorithms::join 如何保存`std :: vector <uchar> `进入`std :: ostream`? - How to save `std::vector<uchar>` into `std::ostream`? 将 boost IOStreams 与 std::ostream_iterator 一起使用 - Using boost IOStreams with std::ostream_iterator boost :: join和boost :: transformed - boost::join and boost::transformed 提高std :: vector的Multiarray - Boost Multiarray of std::vector std :: vector:无法绑定&#39;std :: ostream {aka std :: basic_ostream <char> &#39;&#39;左右&#39;到&#39;std :: basic_ostream <char> &amp;&amp;” - std::vector : cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&' 必须在 std::vector 中加入 std::thread<std::thread> 两次以避免从线程 dtor 终止 - Has to join std::thread in std::vector<std::thread> twice to avoid termination from thread dtor
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM