如何将一个stringvector内插到一个string(优雅的方式)

我正在寻找最优雅的方式来把一个stringvector插入到一个string中。 以下是我现在使用的解决scheme:

static std::string& implode(const std::vector<std::string>& elems, char delim, std::string& s) { for (std::vector<std::string>::const_iterator ii = elems.begin(); ii != elems.end(); ++ii) { s += (*ii); if ( ii + 1 != elems.end() ) { s += delim; } } return s; } static std::string implode(const std::vector<std::string>& elems, char delim) { std::string s; return implode(elems, delim, s); } 

那里有其他人吗?

这可能不是很明显,但在implode添加string时,您正在执行大量的内存分配和释放操作。 一个可能的改进是为一次reserve() ,然后是所有的添加。

使用boost::algorithm::join(..)

 #include <boost/algorithm/string/join.hpp> ... std::string joinedString = boost::algorithm::join(elems, delim); 

另见这个问题 。

你应该使用std::ostringstream而不是std::string来构build输出(然后你可以在最后调用它的str()方法来得到一个string,所以你的接口不需要改变,只是临时s )。

从那里,你可以改变使用std::ostream_iterator ,就像这样:

 copy(elems.begin(), elems.end(), ostream_iterator<string>(s, delim)); 

但是这有两个问题:

  1. delim现在需要是一个const char* ,而不是一个char 。 没什么大不了。
  2. std::ostream_iterator在每个元素(包括最后一个元素)之后写入分隔符。 所以你最后可能需要清除最后一个,或者编写自己的没有这个烦恼的迭代器版本。 如果你有很多代码需要这样的事情,那么值得做后者; 否则整个混乱可能是最好的避免(即使用ostringstream而不是ostream_iterator )。
 std::vector<std::string> strings; const char* const delim = ", "; std::ostringstream imploded; std::copy(strings.begin(), strings.end(), std::ostream_iterator<std::string>(imploded, delim)); 

(包括<string><vector><sstream><iterator>

如果你想有一个干净的结束(没有尾随分隔符)看看这里

 string join(const vector<string>& vec, const char* delim) { stringstream res; copy(vec.begin(), vec.end(), ostream_iterator<string>(res, delim)); return res.str(); } 

因为我喜欢单行(对于各种奇怪的东西非常有用,就像你会看到的那样),下面是一个使用std :: accumulate和C ++ 11 lambda的解决scheme:

 std::accumulate(alist.begin(), alist.end(), std::string(), [](const std::string& a, const std::string& b) -> std::string { return a + (a.length() > 0 ? "," : "") + b; } ) 

我发现这个语法对于stream操作符很有用,我不希望在stream操作中出现各种奇怪的逻辑,只是做一个简单的string连接。 例如,考虑使用stream操作符(使用std;)来格式化string的方法的return语句:

 return (dynamic_cast<ostringstream&>(ostringstream() << "List content: " << endl << std::accumulate(alist.begin(), alist.end(), std::string(), [](const std::string& a, const std::string& b) -> std::string { return a + (a.length() > 0 ? "," : "") + b; } ) << endl << "Maybe some more stuff" << endl )).str(); 

一个使用std::accumulate版本:

 #include <numeric> #include <iostream> #include <string> struct infix { std::string sep; infix(const std::string& sep) : sep(sep) {} std::string operator()(const std::string& lhs, const std::string& rhs) { std::string rz(lhs); if(!lhs.empty() && !rhs.empty()) rz += sep; rz += rhs; return rz; } }; int main() { std::string a[] = { "Hello", "World", "is", "a", "program" }; std::string sum = std::accumulate(a, a+5, std::string(), infix(", ")); std::cout << sum << "\n"; } 

这是另一个不添加最后一个元素后面的分隔符:

 std::string concat_strings(const std::vector<std::string> &elements, const std::string &separator) { if (!elements.empty()) { std::stringstream ss; auto it = elements.cbegin(); while (true) { ss << *it++; if (it != elements.cend()) ss << separator; else return ss.str(); } } return ""; 

特别是对于更大的集合,你想避免检查你是否仍然添加第一个元素或不确保没有尾随分隔符…

所以对于空元素或单元素列表,根本就没有迭代。

空的范围是微不足道的:return“”。

单元素或多元素可以通过accumulate完美处理:

 auto join = [](const auto &&range, const auto separator) { if (range.empty()) return std::string(); return std::accumulate( next(begin(range)), // there is at least 1 element, so OK. end(range), range[0], // the initial value [&separator](auto result, const auto &value) { return result + separator + value; }); }; 

运行示例( 需要C ++ 14 ): http : //cpp.sh/8uspd

稍长的解决scheme,但不使用std::ostringstream ,并不需要一个破解删除最后一个分隔符。

http://www.ideone.com/hW1M9

和代码:

 struct appender { appender(char d, std::string& sd, int ic) : delim(d), dest(sd), count(ic) { dest.reserve(2048); } void operator()(std::string const& copy) { dest.append(copy); if (--count) dest.append(1, delim); } char delim; mutable std::string& dest; mutable int count; }; void implode(const std::vector<std::string>& elems, char delim, std::string& s) { std::for_each(elems.begin(), elems.end(), appender(delim, s, elems.size())); } 

只需添加! String s =“”;

 for (int i = 0; i < doc.size(); i++) //doc is the vector s += doc[i]; 

首先,这里需要一个stream类ostringstream来进行多次连接,并节省了过多的内存分配的底层麻烦。

码:

 string join(const vector<string>& vec, const char* delim) { ostringstream oss; if(!string_vector.empty()) { copy(string_vector.begin(),string_vector.end() - 1, ostream_iterator<string>(oss, delim.c_str())); } return oss.str(); } vector<string> string_vector {"1", "2"}; string delim("->"); string joined_string = join(); // get "1->2" 

说明:

思考时,把oss这里当作std::cout

当我们想写:

std::cout << string_vector[0] << "->" << string_vector[1] << "->"

我们可以使用下面的STL类作为帮助:

ostream_iterator在每次使用<<时自动附加一个带有分隔符的包装输出stream。

例如,

ostream my_cout = ostream_iterator<string>(std::cout, "->")

std:cout包装为my_cout

所以每次你my_cout << "string_vector[0]"

它意味着std::cout << "string_vector[0]" << "->"

至于copy(vector.begin(), vector.end(), std::out);

它意味着std::cout << vector[0] << vector[1] (...) << vector[end]

这是我使用的,简单而灵活

 string joinList(vector<string> arr, string delimiter) { if (arr.empty()) return ""; string str; for (auto i : arr) str += i + delimiter; str = str.substr(0, str.size() - delimiter.size()); return str; } 

使用:

 string a = joinList({ "a", "bbb", "c" }, "!@#"); 

输出:

 a!@#bbb!@#c