Простой способ разделить последовательность строк, разделенных нулями, в С++

У меня есть ряд строк, хранящихся в одном массиве, разделенных нулями (например, ['f', 'o', 'o', '\ 0', 'b', 'a', 'r', '\ 0'...]), и мне нужно разбить это на std::vector<std::string> или подобное.

Я мог бы просто написать 10-строчный цикл, чтобы сделать это, используя std::find или strlen (на самом деле я это сделал), но мне интересно, есть ли более простой/более элегантный способ сделать это, для например, некоторый алгоритм STL, который я упустил, который можно уговорить на это.

Это довольно простая задача, и меня не удивило бы, если бы была какая-то хитроумная хитрость STL, которая может быть применена, чтобы сделать ее еще проще.

Любые участники?

Ответы

Ответ 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 );

Ответ 2

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")));

Ответ 3

Далее полагается 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.

Ответ 4

Здесь решение я придумал сам, предполагая, что буфер заканчивается сразу после последней строки:

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;
}

Ответ 5

Плохой ответ, на самом деле, но я сомневался в вашем заявлении о 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';
}

Ответ 6

Более элегантное и актуальное решение (по сравнению с моим другим ответом) использует 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.

Ответ 7

В 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;
}

Это не С++, но он будет работать