c++ - Getting string tokens / params as parsing -
c++ - Getting string tokens / params as parsing -
i've been trying hard plenty find way in c++ tokens , params in script file of own, can in c# using regex , need in c++
let's i've script file:
name = tywin lanninster age = 35 customattributes = { health = 100, mana = 100, height = 4, weight = 40 } what need know how interat through code, , trigger between tokens? name value, age value, , info within behavior while beingness able it's value? it's beingness able parse it, i've boost spirit isn't i'm looking for, i've seen std::string has find_first_of function, i'm looking answers.
i've found question mine 2007, code given isn't plenty it's incomplete, can see it's i'm looking for: http://www.daniweb.com/software-development/cpp/threads/76797/simple-script-parser-how-to-
please help me!
so i've made this:
this first load loop parsing:
while (getline(file, text)) { if (!getnexttoken()) continue; std::cout << "token: '" << token << "'" << std::endl; if (token == "name") { getstring(); } else { std::cout << "unknown token: '" << token << "'" << std::endl; } } the function utilize getting tokens, i'm able obtain things age & name
bool script::getnexttoken() char letter; (int = 0; != text.size(); i++) { letter = text[i]; if (letter == token_equal) { token = text.substr(0, i-1); text.erase(0, i+2); homecoming true; } } homecoming false; } the code utilize getting strings within "
bool script::getstring() char letter; std::string str; std::cout << "trying string from: " << text << std::endl; (int = 0; != text.size() + 1; i++) { letter = text[i]; if (letter == token_string) { text.erase(0, 1); int pos = text.find_first_of(token_string); str = text.substr(i, pos); std::cout << "string found: " << str << std::endl; text.erase(pos); std::cout << "text left: " << text << std::endl; break; } } but i've no thought how things within { } since in different lines , i'm using getline
update:
given file format tad more complex first thought, gave shot using boost-spirit time. indeed, it's tedious enterprise work more complicated trivial examples of tutorial, little help stackoverflow entries, managed working.
here goes:
#include <boost/config/warning_disable.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix_core.hpp> #include <boost/spirit/include/phoenix_operator.hpp> #include <boost/spirit/include/phoenix_object.hpp> #include <boost/spirit/include/support_istream_iterator.hpp> #include <boost/fusion/include/adapt_struct.hpp> #include <boost/fusion/include/io.hpp> #include <iostream> #include <fstream> #include <string> namespace info { namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; struct custom_attributes { /* custom_attributes(int h = 0, int m = 0, int ht = 0, int w = 0): health(h), mana(m), height(ht), weight(w){} */ int health; int mana; int height; int weight; }; struct player { /* player(std::string n="", int a=0, custom_attributes at={}): name(n), age(a), attrs(at) {} */ std::string name; int age; custom_attributes attrs; }; } boost_fusion_adapt_struct( data::custom_attributes, (int, health) (int, mana) (int, height) (int, weight) ) boost_fusion_adapt_struct( data::player, (std::string, name) (int, age) (data::custom_attributes, attrs) ) namespace info { template <typename iterator> struct attributes_parser : qi::grammar<iterator, custom_attributes(), ascii::space_type> { attributes_parser() : attributes_parser::base_type(start) { using qi::int_; using qi::lit; using qi::lexeme; using ascii::char_; using ascii::space_type; start %= lit("customattributes") >> '=' >> '{' >> lit("health") >> '=' >> int_ >> ',' >> lit("mana") >> '=' >> int_ >> ',' >> lit("height") >> '=' >> int_ >> ',' >> lit("weight") >> '=' >> int_ >> '}' ; } qi::rule<iterator, custom_attributes(), ascii::space_type> start; }; template <typename iterator> struct player_parser : qi::grammar<iterator, player(), ascii::space_type> { player_parser() : player_parser::base_type(start) { using qi::int_; using qi::lit; using qi::lexeme; using ascii::char_; using ascii::space_type; quoted_string %= lexeme[+(char_ - '"')]; start %= lit("name") >> '=' >> '"' >> quoted_string >> '"' >> lit("age") >> '=' >> int_ >> attributes ; } qi::rule<iterator, std::string(), ascii::space_type> quoted_string; qi::rule<iterator, player(), ascii::space_type> start; attributes_parser<iterator> attributes; }; } int main(){ using boost::spirit::ascii::space; typedef boost::spirit::istream_iterator iterator_type; typedef data::player_parser<iterator_type> player_parser; player_parser g; data::player plr; std::ifstream in("player.txt"); in.unsetf(std::ios::skipws); iterator_type iter(in), end; bool r = phrase_parse(iter, end, g, space, plr); if (r && iter == end){ std::cout << "parsing succeeded:" << std::endl; std::cout << " name = " << plr.name << std::endl; std::cout << " age = " << plr.age << std::endl; std::cout << " health = " << plr.attrs.health << std::endl; std::cout << " mana = " << plr.attrs.mana << std::endl; std::cout << " height = " << plr.attrs.height << std::endl; std::cout << " weight = " << plr.attrs.weight << std::endl; } else { std::cout << "parsing failed" << std::endl; } } a few points:
i used version 1.49 of boost this.
the above code works on sample provided in question, if stored in file (aptly named player.txt) , , with double quotes around strings meant values, , not keywords, instance value name attribute.
i chose split grammar in two, reuse , extend attribute section. seems reasonable guess you'll headed next. however, means back upwards boost-fusion serialization difficult. there entries on stackoverflow dealing issue. please check'em out, , inquire 1 time again if there's problem.
old answer:
since want utilize regex, suppose document's grammar quite simple, , wish read line line. furthermore, sample nowadays in question can tokenized spaces or carriage returns separators.
you utilize iostream , >> operator, , set of combinators (ie. functions doing each simple operation, combine produce more complex ones) each line format.
#include <iostream> #include <stdexcept> #include <vector> using std::string; using std::istream; using std::vector; class parse_exn : public std:runtime_error{ public: parse_exn(const string msg) : runtime_error(msg){} }; bool expect(istream &is, const string atom){ string data; >> data; homecoming is.good() && info == atom; // or throw } int readattribute(istream &is, const string name){ int result; if (expect(is, name) && expect(is,"=")) >> result; if (is.good()) homecoming result; } throw parse_exn("invalid attribute"); } yourclass readstruct(istream &is, const vector<string> attributes){ // parse header (name, "=","{") // parse each attribute , commas // parse footer ("}") // homecoming object // or throw exn if got wrong } yourclass supposed class defined contains info parsed. should idea. please seek writing , come if stuck.
note: above code untested.
c++ parsing token params
Comments
Post a Comment