如何将一个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)); 
但是这有两个问题:
-   delim现在需要是一个const char*,而不是一个char。 没什么大不了。
-   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 ,并不需要一个破解删除最后一个分隔符。 
和代码:
 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