строковый итератор, несовместимый для чтения каждой строки

У меня есть std::ostringstream. Я хотел бы выполнить итерацию для каждой строки этого std::ostringstream.

Я использую boost::tokenizer :

std::ostringstream HtmlStream;
.............
typedef boost::tokenizer<boost::char_separator<char> > line_tokenizer;
line_tokenizer tok(HtmlStream.str(), boost::char_separator<char>("\n\r"));

for (line_tokenizer::const_iterator i = tok.begin(), end = tok.end(); i != end; ++i)
{
    std::string str = *i;
}

На линии

for (line_tokenizer::const_iterator i = tok.begin(), end = tok.end(); i != end; 

У меня есть ошибка утверждения с «несовместимым строковым итератором». Я читал об этой ошибке в Google и в StackOverflow, но мне трудно найти свою ошибку.

Кто-нибудь может мне помочь, пожалуйста?

Большое спасибо,

С наилучшими пожеланиями,

Никсеус


person Walter Fabio Simoni    schedule 02.12.2013    source источник
comment
Поскольку вы, кажется, не возражаете против копии, как насчет того, чтобы скопировать str() в istringstream и использовать std::getline()?   -  person Chad    schedule 03.12.2013
comment
Я новичок в мире boost::, поэтому мне нужно его изучить! Не могли бы вы дать мне пример кода для этого примера? С iStringStream? Спасибо :)   -  person Walter Fabio Simoni    schedule 03.12.2013
comment
@WalterFabioSimoni: я думаю, что Чад имеет в виду создать экземпляр std::istringstream, инициализированный вашей строкой, а затем использовать с ним std::getline() так же, как и файловый поток. Это позволит избежать использования Boost в целом. Это может сработать для вас, но оно не может делать все, что может делать boost::tokenizer (например, игнорировать последовательные символы-разделители).   -  person Fred Larson    schedule 03.12.2013


Ответы (1)


Мне нравится делать это без копирования для отчетов об эффективности/ошибках:

Смотрите Прямой эфир на Coliru

#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <iostream>
#include <vector>

int main()
{
    auto const& s = "hello\r\nworld";

    std::vector<boost::iterator_range<char const*>> lines;
    boost::split(lines, s, boost::is_any_of("\r\n"), boost::token_compress_on);

    for (auto const& range : lines)
    {
        std::cout << "at " << (range.begin() - s) << ": '" << range  << "'\n";
    };
}

Отпечатки:

at 0: 'hello'
at 7: 'world'

Это более эффективно, чем большинство показанных альтернатив. Конечно, если вам нужны дополнительные возможности парсинга, рассмотрите Boost Spirit:

Смотрите Прямой эфир на Coliru

#include <boost/spirit/include/qi.hpp>

int main()
{
    std::string const s = "hello\r\nworld";

    std::vector<std::string> lines;

    {
        using namespace boost::spirit::qi;
        auto f(std::begin(s)), 
             l(std::end(s));
        bool ok = parse(f, l, *(char_-eol) % eol, lines);
    }

    for (auto const& range : lines)
    {
        std::cout << "'" << range  << "'\n";
    };
}
person sehe    schedule 02.12.2013
comment
@LightnessRacesinOrbit вы поймете, для чего вам это нужно :) Или нет. Обратите внимание, что введение ко второму примеру гласит: если вам нужны дополнительные возможности синтаксического анализа. Это означает, что вам нужна проверка ввода в 99% случаев. - person sehe; 03.12.2013
comment
Хоть бы успел const ;) - person Lightness Races in Orbit; 03.12.2013
comment
Я не хотел, чтобы это казалось используемым или даже ограниченным каким-либо образом. Пусть переменная расцветает, какой бы маленькой ни была ее жизнь. Моя религия удерживает меня от уничтожения самой маленькой жизни. - person sehe; 03.12.2013
comment
const продвигает свободу жизни. Свобода распространять правду жизни, а не боль смерти, которая приходит с неожиданными мутациями! (читай: рак) - person Lightness Races in Orbit; 03.12.2013
comment
Спасибо ! Ваш первый пример можно использовать с моим ostringstream? - person Walter Fabio Simoni; 03.12.2013
comment
Это точно. В вашем примере кода вы все равно используете только резервное хранилище std::stringbuf (.str()). Вот почему я показал шаги оттуда. - person sehe; 03.12.2013
comment
как я могу использовать переменную const& range как строку? Например, чтобы использовать функцию поиска? - person Walter Fabio Simoni; 03.12.2013
comment
@WalterFabioSimoni Это уже строка. В первом примере я решил вместо этого показать boost::iterator_range, просто чтобы покрасоваться. Замените его на std::string, и он будет работать точно так же. Также обратите внимание, что оба примера уже используют переменную const& range в виде строки. Образец печатает строки :) - person sehe; 04.12.2013