Parse plain python double list

What is the best way to parse a string (the number of elements is not fixed):

[ 0.0125, 2.9518e+02, 1.2833e+00, -3.5302e-04, 1.2095e+01, 1.0858e-01, 1.2112e-04, 1.1276e+03 ] # comments 

to get a std::vector of double in c ++? I have done this:

 vector<double> read_line(string line) { vector<double> coefficients_line; // erase all before [ and all after ] size_t found1 = line.find("["); if (found1 == string::npos) cerr << "line not valid: " << line; line.erase(line.begin(), line.begin() + found1 + 1); size_t found2 = line.find("]"); if (found2 == string::npos) cerr << "line not valid: " << line; line.erase(line.begin() + found2, line.end()); vector<string> coefficients_string; boost::split(coefficients_string, line, boost::is_any_of(",")); for (vector<string>::const_iterator ic=coefficients_string.begin(); ic!=coefficients_string.end(); ++ic) { cout << "c string \"" << *ic << "\"" << endl; string s = *ic; boost::trim(s); double c = boost::lexical_cast<double>(s); cout << "c double: " << c << endl; coefficients.push_back(c); } return coefficients; } 

non-exciting but convenient solutions are welcome

+4
source share
3 answers

Given the format, I think it's quite simple to use I / O streams.

 #include <iostream> #include <sstream> #include <vector> int main() { std::istringstream line("[ 1.23, 1.24e+3, 3, 1.44e-2 ]"); char c; while ((line >> c) && c != '['); if (!line) { return 1; } std::vector<double> v; double d; while ((line >> d)) { v.push_back(d); line >> c; if (c != ',') { break; } } for (std::vector<double>::const_iterator i = v.begin(), e = v.end(); i != e; ++i) { std::cout << *i << "\n"; } return 0; } 

Print

 1.23 1240 3 0.0144 

(In action on ideone )

This is not a complete parsing, and it will accept the wrong inputs (in particular, it doesn’t check ] at the end. But I would say that it is pretty decent.

+2
source

I see you are already using boost . You should try boost.spirit.qi for this purpose.

 #include <vector> #include <string> #include <iostream> #include <boost/spirit/include/qi.hpp> namespace qi = ::boost::spirit::qi; template <typename Iterator> bool parse_numbers(Iterator & first, Iterator last, std::vector<double> & v) { using qi::double_; using qi::phrase_parse; using qi::_1; using boost::spirit::ascii::space; return phrase_parse(first, last, ('[' >> double_ % ',' >> ']'), space, v); } int main() { std::string s = "[ 0.0125, 2.9518e+02, 1.2833e+00, -3.5302e-04, 1.2095e+01, 1.0858e-01, 1.2112e-04, 1.1276e+03 ] # comments"; std::vector<double> v; std::string::iterator sb = s.begin(); parse_numbers(sb, s.end(), v); std::cout << "Parsed numbers:" << std::endl; for (int i = 0; i < v.size(); ++i) std::cout << v[i] << std::endl; std::cout << "Rest of line:" << std::endl; std::cout << std::string(sb, s.end()) << std::endl; } 

I took the parse_numbers() function from the spirit documentation and adapted it a bit. It returns false when the parsing failed (i.e. the Unformed list), but returns true when the line has text after the list: the first iterator ( sb in main() ) will indicate where the list of numbers ended.

See the full list of documents:
http://www.boost.org/doc/libs/1_46_1/libs/spirit/doc/html/spirit/qi.html

+2
source

If your compiler supports C ++ 0x, you can use AX to parse this line:

 std::vector<double> read_line(std::string line) { std::vector<double> v; auto spaces = *axe::r_any(" \t\n\r"); double d; auto double_rule = spaces & axe::r_double(d) >> axe::e_ref([](...){ v.push_back(d); }); auto array_rule = '[' & double_rule % ',' & ']'; array_rule(line.begin(), line.end()); return v; } 

PS I have not tested it, so surface errors are possible.

0
source

All Articles