C++ 如何将字符串向量内爆为字符串(优雅的方式)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5689003/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to implode a vector of strings into a string (the elegant way)
提问by ezpresso
I'm looking for the most elegant way to implode a vector of strings into a string. Below is the solution I'm using now:
我正在寻找将字符串向量内爆为字符串的最优雅方法。以下是我现在使用的解决方案:
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);
}
Is there any others out there?
还有其他人吗?
回答by Andre Holzner
Use boost::algorithm::join(..)
:
使用boost::algorithm::join(..)
:
#include <boost/algorithm/string/join.hpp>
...
std::string joinedString = boost::algorithm::join(elems, delim);
See also this question.
另请参阅此问题。
回答by sehe
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));
(include <string>
, <vector>
, <sstream>
and <iterator>
)
(包括<string>
、<vector>
、<sstream>
和<iterator>
)
If you want to have a clean end (no trailing delimiter) have a look here
回答by John Zwinck
You should use std::ostringstream
rather than std::string
to build the output (then you can call its str()
method at the end to get a string, so your interface need not change, only the temporary s
).
您应该使用std::ostringstream
而不是std::string
构建输出(然后您可以str()
在最后调用其方法来获取字符串,因此您的界面不需要更改,只需临时s
)。
From there, you could change to using std::ostream_iterator
, like so:
从那里,您可以更改为 using std::ostream_iterator
,如下所示:
copy(elems.begin(), elems.end(), ostream_iterator<string>(s, delim));
But this has two problems:
但这有两个问题:
delim
now needs to be aconst char*
, rather than a singlechar
. No big deal.std::ostream_iterator
writes the delimiter after every single element, including the last. So you'd either need to erase the last one at the end, or write your own version of the iterator which doesn't have this annoyance. It'd be worth doing the latter if you have a lot of code that needs things like this; otherwise the whole mess might be best avoided (i.e. useostringstream
but notostream_iterator
).
delim
现在需要是一个const char*
,而不是一个char
。没什么大不了。std::ostream_iterator
在每个元素之后写入定界符,包括最后一个。所以你要么需要在最后擦除最后一个,要么编写你自己的迭代器版本,它没有这个烦恼。如果您有很多代码需要这样的东西,那么做后者是值得的;否则最好避免整个混乱(即使用ostringstream
但不使用ostream_iterator
)。
回答by Guss
Because I love one-liners (they are very useful for all kinds of weird stuff, as you'll see at the end), here's a solution using std::accumulate and C++11 lambda:
因为我喜欢单行(它们对各种奇怪的东西都非常有用,你会在最后看到),这里有一个使用 std::accumulate 和 C++11 lambda 的解决方案:
std::accumulate(alist.begin(), alist.end(), std::string(),
[](const std::string& a, const std::string& b) -> std::string {
return a + (a.length() > 0 ? "," : "") + b;
} )
I find this syntax useful with stream operator, where I don't want to have all kinds of weird logic out of scope from the stream operation, just to do a simple string join. Consider for example this return statement from method that formats a string using stream operators (using std;):
我发现这个语法对流操作符很有用,我不想在流操作范围之外有各种奇怪的逻辑,只是为了做一个简单的字符串连接。例如,考虑使用流运算符(使用 std;)格式化字符串的方法的返回语句:
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();
回答by BlackMamba
string join(const vector<string>& vec, const char* delim)
{
stringstream res;
copy(vec.begin(), vec.end(), ostream_iterator<string>(res, delim));
return res.str();
}
回答by xtofl
Especially with bigger collections, you want to avoid having to check if youre still adding the first element or not to ensure no trailing separator...
特别是对于较大的集合,您希望避免检查您是否仍在添加第一个元素以确保没有尾随分隔符...
So for the empty or single-element list, there is no iteration at all.
所以对于空或单元素列表,根本没有迭代。
Empty ranges are trivial: return "".
空范围是微不足道的:返回“”。
Single element or multi-element can be handled perfectly by accumulate
:
可以通过以下方式完美处理单个元素或多元素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;
});
};
Running sample (require C++14): http://cpp.sh/8uspd
运行示例(需要 C++14):http: //cpp.sh/8uspd
回答by Sasa Milenkovic
I like to use this one-liner accumulate (no trailing delimiter):
我喜欢使用这种单行累加(无尾随分隔符):
std::accumulate(
std::next(elems.begin()),
elems.end(),
elems[0],
[](std::string a, std::string b) {
return a + delimiter + b;
}
);
回答by Rob?
A version that uses std::accumulate
:
使用的版本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";
}
回答by user3545770
what about simple stupid solution?
简单的愚蠢解决方案怎么样?
std::string String::join(const std::vector<std::string> &lst, const std::string &delim)
{
std::string ret;
for(const auto &s : lst) {
if(!ret.empty())
ret += delim;
ret += s;
}
return ret;
}
回答by Darien Pardinas
Here is another one that doesn't add the delimiter after the last element:
这是另一个不在最后一个元素后添加分隔符的元素:
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 "";