1

I have an std::ostringstream. I would like to iterate for each line of this std::ostringstream.

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

On the line

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

I have an assert error with "string iterator incompatible". I have read about this error, on google and on StackOverflow too, but i have diffuclty to find my error.

Anyone could help me please ?

Thanks a lot,

Best regards,

Nixeus

Walter Fabio Simoni
  • 5,671
  • 15
  • 55
  • 80
  • Since you don't seem to mind a copy, how about copying the `str()` into an `istringstream` and using `std::getline()`? – Chad Dec 02 '13 at 21:35
  • I'm new in the boost:: "world" so i need to learn it !Could you please give me a sample code for this example ? With iStringStream? Thx :) – Walter Fabio Simoni Dec 02 '13 at 21:54
  • 1
    @WalterFabioSimoni: I think Chad means to create an instance `std::istringstream` initialized with your string and then use `std::getline()` with it just as you would a file stream. This would avoid using Boost altogether. It could work for you, but it can't do all that `boost::tokenizer` can do (such as ignoring consecutive delimiter characters). – Fred Larson Dec 02 '13 at 22:11

1 Answers1

2

I like to make it non-copying for efficiency/error reporting:

See it Live on 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";
    };
}

Prints:

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

This is more efficient than most of the alternatives shown. Of course, if you need more parsing capabilities, consider Boost Spirit:

See it Live on 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";
    };
}
sehe
  • 374,641
  • 47
  • 450
  • 633
  • `warning: variable \`ok' is unused` – Lightness Races in Orbit Dec 03 '13 at 00:06
  • @LightnessRacesinOrbit you'll figure out what you need to use it for :) Or not. Note the introduction to the second sample reads: "if you need more parsing capabilities". This implies you need input validation, 99% of the time. – sehe Dec 03 '13 at 00:12
  • Could at least have made it `const` ;) – Lightness Races in Orbit Dec 03 '13 at 00:33
  • I didn't want to make it feel _used_ or even _restricted_ in any way. Let the variable blossom, however small it's lifetime. My religion keeps me from crushing the smallest life. – sehe Dec 03 '13 at 00:37
  • `const` promotes _freedom_ of life. Freedom to spread the _truth_ of life rather than the pain of death that comes with unexpected mutation! (read: cancer) – Lightness Races in Orbit Dec 03 '13 at 01:19
  • Thanks ! Your first example is uable with my ostringstream ? – Walter Fabio Simoni Dec 03 '13 at 13:05
  • It sure is. In your sample code you only use the backing storage of the std::stringbuf (`.str()`) anyways. So, that's why I showed steps _from there_. – sehe Dec 03 '13 at 13:40
  • how can i use the const& range variable as a string ? In order to use "find" function for example ? – Walter Fabio Simoni Dec 03 '13 at 18:01
  • @WalterFabioSimoni It already is a string. In the first example I elected to show `boost::iterator_range` instead, just to show off. Replace it with `std::string` and it will work exactly the same. Also, note, both examples _already_ "us the const& range variable as a string". The sample prints the strings :) – sehe Dec 03 '13 at 21:56