[英]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.