Ответ 1
Мои два цента:
const char* p = str;
std::vector<std::string> vector;
do {
vector.push_back(std::string(p));
p += vector.back().size() + 1;
} while ( // whatever condition applies );
У меня есть ряд строк, хранящихся в одном массиве, разделенных нулями (например, ['f', 'o', 'o', '\ 0', 'b', 'a', 'r', '\ 0'...]), и мне нужно разбить это на std::vector<std::string>
или подобное.
Я мог бы просто написать 10-строчный цикл, чтобы сделать это, используя std::find
или strlen
(на самом деле я это сделал), но мне интересно, есть ли более простой/более элегантный способ сделать это, для например, некоторый алгоритм STL, который я упустил, который можно уговорить на это.
Это довольно простая задача, и меня не удивило бы, если бы была какая-то хитроумная хитрость STL, которая может быть применена, чтобы сделать ее еще проще.
Любые участники?
Мои два цента:
const char* p = str;
std::vector<std::string> vector;
do {
vector.push_back(std::string(p));
p += vector.back().size() + 1;
} while ( // whatever condition applies );
Boost solution:
#include <boost/algorithm/string.hpp>
std::vector<std::string> strs;
//input_array must be a Range containing the input.
boost::split(
strs,
input_array,
boost::is_any_of(boost::as_array("\0")));
Далее полагается std::string
с неявным конструктором, принимающим a const char*
, что делает цикл очень простым двухстрочным:
#include <iostream>
#include <string>
#include <vector>
template< std::size_t N >
std::vector<std::string> split_buffer(const char (&buf)[N])
{
std::vector<std::string> result;
for(const char* p=buf; p!=buf+sizeof(buf); p+=result.back().size()+1)
result.push_back(p);
return result;
}
int main()
{
std::vector<std::string> test = split_buffer("wrgl\0brgl\0frgl\0srgl\0zrgl");
for (auto it = test.begin(); it != test.end(); ++it)
std::cout << '"' << *it << "\"\n";
return 0;
}
Это решение предполагает, что размер буфера известен и критерий для конца списка строк. Если список заканчивается вместо "\0\0"
, условие в цикле необходимо изменить с p!=foo+sizeof(foo)
на *p
.
Здесь решение я придумал сам, предполагая, что буфер заканчивается сразу после последней строки:
std::vector<std::string> split(const std::vector<char>& buf) {
auto cur = buf.begin();
while (cur != buf.end()) {
auto next = std::find(cur, buf.end(), '\0');
drives.push_back(std::string(cur, next));
cur = next + 1;
}
return drives;
}
Плохой ответ, на самом деле, но я сомневался в вашем заявлении о 10-линейном цикле для ручного разделения. 4 строки делают это для меня:
#include <vector>
#include <iostream>
int main() {
using std::vector;
const char foo[] = "meh\0heh\0foo\0bar\0frob";
vector<vector<char> > strings(1);
for (const char *it=foo, *end=foo+sizeof(foo); it!=end; ++it) {
strings.back().push_back(*it);
if (*it == '\0') strings.push_back(vector<char>());
}
std::cout << "number of strings: " << strings.size() << '\n';
for (vector<vector<char> >::iterator it=strings.begin(), end=strings.end();
it!=end; ++it)
std::cout << it->data() << '\n';
}
Более элегантное и актуальное решение (по сравнению с моим другим ответом) использует getline и сводится к двум строкам только с С++ 2003, и не требуется ручная ручная бухгалтерия и кондиционирование:
#include <iostream>
#include <sstream>
#include <string>
int main() {
const char foo[] = "meh\0heh\0foo\0bar\0frob";
std::istringstream ss (std::string(foo, foo + sizeof foo));
std::string str;
while (getline (ss, str, '\0'))
std::cout << str << '\n';
}
Однако обратите внимание, как конструктор строк на основе диапазона уже указывает на неотъемлемую проблему с splitting-at-'\ 0: вы должны знать точный размер или найти какой-либо другой char -combo для Ultimate Terminator.
В C, string.h имеет этого парня:
char * strtok ( char * str, const char * delimiters );
пример на cplusplus.com:
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
Это не С++, но он будет работать