2

Possible Duplicate:
Parsing a comma-delimited std::string

I want to parse a string into an integer vector:

string s = "1;2;4;8;16;";
vector<int> n = parse_string(s);
// n == [1, 2, 4, 8, 16];

Of course, I can write a simple code with strtok and atoi. But, what would be a much shorter code with C++ boost? I never tried with Boost, but heard that it could simply your code pretty much as if using Python.

Community
  • 1
  • 1
Nullptr
  • 3,103
  • 4
  • 27
  • 28
  • 4
    I think this question has been asked a few times already: http://stackoverflow.com/questions/1894886/parsing-a-comma-delimited-stdstring http://stackoverflow.com/questions/4328685/input-line-by-line-from-an-input-file-and-tokenize-using-strtok-and-the-output http://stackoverflow.com/questions/536148/c-string-parsing-python-style http://stackoverflow.com/questions/1511029/c-tokenize-a-string-and-include-delimiters http://stackoverflow.com/questions/3162108/a-better-way-to-split-a-string-into-an-array-of-strings-in-c-c-using-whitespac – Jared Krumsie Dec 10 '11 at 04:29

5 Answers5

3

It can be done without Boost:

string s = "1;2;4;8;16";
vector<int> n;
transform(s.begin(), s.end(), [](char c){return c == ';' ? ' ' : c});
stringstream ss(s);
copy(istream_iterator<int>(ss), istream_iterator<int>(), back_inserter(n));

EDIT: If you wanna use only C++03 code you must write:

char semicolon_to_space(char c){
  return c == ';' ? ' ' : c
};

// ...

string s = "1;2;4;8;16";
vector<int> n;
transform(s.begin(), s.end(), semicolon_to_space);
stringstream ss(s);
copy(istream_iterator<int>(ss), istream_iterator<int>(), back_inserter(n))
Hauleth
  • 22,873
  • 4
  • 61
  • 112
1

I'm not a boost profi, so my code is not ideal:

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

int main() 
{
    using namespace boost::algorithm;

    std::vector< std::string > result;
    split(result, "1;2;4;8;16;", is_any_of(";"));

    BOOST_FOREACH(const std::string& item, result)
    {
        std::cout << item << std::endl;
    }
}

you can dispose of is_any_of for sure

Alek86
  • 1,489
  • 3
  • 17
  • 26
0

I think that there are 2 separate algorithms should be used in this case. The first one will be a parser which will separate your values boost::split http://www.boost.org/doc/libs/1_48_0/doc/html/string_algo/reference.html#header.boost.algorithm.string.split_hpp should help. The second one will be the lexical cast which will convert your string integers to int values take a look to boost::lexical_cast<>.

AlexTheo
  • 4,004
  • 1
  • 21
  • 35
-1

uhm boost::tokenizer? Wondering if I'm missing something, but isn't that ideal for this application?

Example on http://www.boost.org/doc/libs/1_43_0/libs/tokenizer/char_separator.htm < that page can easily be modified to the needs here.

paul23
  • 8,799
  • 12
  • 66
  • 149
-1

Its easier if they are space separated:
If that is a requirement that is easily added.

#include <vector>
#include <iterator>
#include <algorithm>

int main()
{
    string s = "1 2 4 8 16";
    std::stringstream s_stream(s);

    vector<int> n;
    std::copy(std::istream_iterator<int>(s_stream), std::istream_iterator<int>(),
              std::back_inserter(n)
             );
}

If you must have the ';' then a simple converter class can be inserted.

struct IntReader
{
    int value;
    operator int() {return value;}
    friend std::istream& operator>>(std::istream& stream, IntReader& data)
    {
        char x = 0;
        if ((stream >> data.value >> x) && (x != ';'))
        {   stream.setstate(std::ios::failbit);
        }
        return stream;
    }
};

Then just change the copy to use it:

    std::copy(std::istream_iterator<IntReader>(s_stream), std::istream_iterator<IntReader>(),
              std::back_inserter(n)
             );
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • I have added initialization of the `x` variable, I hope you don't mind. Additionally, I am not sure of the implementation of the `operator>>`. If `(stream >> data.value >>x)`, then the `stream` should never have the `failbit` set. Maybe the condition should be negated? – David Rodríguez - dribeas Dec 09 '11 at 23:24
  • @DavidRodríguez-dribeas: I don't think initialization of x is necassery. In `stream >> data.value >> x` If any part fails then then failbit is already set and I do not need to do anything. If it work then we need to check the value of x. But since it worked we know it has been initialized and thus the check for `x != ';'` is valid. Thus if the read worked and x is not ';' then we set the fail bit. – Martin York Dec 10 '11 at 05:07
  • Then the `if` reads: *if we have correctly read the number and another character that is not `;` then clear the failbit*? If we have read correctly (necessary by the first half of the condition, then `failbit` is not set and thus the body of the `if` is useless, right? My problem is that I am not understanding the intent, should it be a `setstate` rather than a `clear`? *If we read the number and a character, but the character is not a `;` then something went wrong?* – David Rodríguez - dribeas Dec 10 '11 at 08:33
  • It's supposed to set the failbbit. My brain is obviously not working. Thanks. – Martin York Dec 10 '11 at 16:39