获取字符串标记/参数作为解析

时间:2014-06-19 05:30:40

标签: c++ parsing token params

我一直在努力寻找C ++中的方法来获取我自己的脚本文件中的令牌和参数,我可以使用正则表达式在C#中执行此操作,但我需要在C ++中执行此操作< / p>

让我们说这个脚本文件:

Name = Tywin Lanninster
Age = 35

CustomAttributes = {
 Health = 100,
 Mana = 100,
 Height = 4,
 Weight = 40
}

我需要知道的是如何通过所有这些代码进行交互,并在令牌之间触发? 就像获取名称值,年龄值,然后获取行为中的所有数据,同时还能获得它的价值?它就像能够解析它一样,我已经提升但精神并不是我想要的,我已经看到std::string有{{{} 1}}功能,所以我正在寻找答案。

我从2007年发现了一个类似我的问题,但由于代码不完整而给出的代码不够,但可以看到我正在寻找的代码:http://www.daniweb.com/software-development/cpp/threads/76797/simple-script-parser-how-to-

请帮助我!

所以我做了这个:

这是我的第一个解析加载循环:

find_first_of

我用来获取令牌的功能,我能够获得像Age和amp;这样的东西。名称

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

我用来获取字符串的代码&#34;

bool Script::getNextToken()
char letter;

    for (int i = 0; i != text.size(); i++)
    {
        letter = text[i];
        if (letter == TOKEN_EQUAL)
        {
            token = text.substr(0, i-1);
            text.erase(0, i+2);
            return true;
        }
    }

    return false;
}

但是我不知道如何把事情弄到{}里面,因为它们在不同的行中而且我使用了getline

1 个答案:

答案 0 :(得分:0)

更新

鉴于你的文件格式比我最初想的要复杂得多,我这次用给了它另一个镜头。实际上,使用比教程的简单示例更复杂的东西来处理它是一项单调乏味的事情,但是在stackoverflow条目的帮助下,我设法得到了一些工作。

这就是:

#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 data {

  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 data {
  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;

  }
}

几点:

我使用了1.49版本的增强功能。

上面的代码适用于问题中提供的示例,如果存储在一个文件中(恰当地命名为player.txt),而带有双引号的字符串,这些字符串应该是值,而不是关键字,例如 Name 属性的值。

我选择将语法分成两部分,以便您可以重用和扩展属性部分。对于你接下来要去哪里似乎是一个合理的猜测。但是,这意味着对 序列化的支持将很困难。 stackoverflow上有条目处理该问题。请检查一下,然后再问一下是否有问题。


旧答案:

由于你想使用正则表达式,我认为文档的语法非常简单,你希望逐行阅读它。此外,您在问题中提供的样本可以使用空格或回车符号作为分隔符进行标记。

你可以简单地使用iostream和>>运算符,以及一组组合器(即每个简单操作的函数,组合起来生成更复杂的函数)。

#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;
    Is >> data;
    return is.good() && data == atom; // or throw
}

int readAttribute(istream &is, const string name){
    int result;
    if (expect(is, name) && expect(is,"="))
        is >> result;
        If (is.good())
            return result;
    }
    throw parse_exn("invalid attribute");
}

 Yourclass readStruct(istream &is, const vector<string> attributes){
    // parse header (name, "=","{")
    // parse each attribute and commas
    // parse footer ("}")
    // return the object
    // or throw an exn if something got wrong
}

Yourclass应该是您定义的类,其中包含您解析的数据。你应该明白这个想法。现在请尝试写一些东西,如果你遇到困难就回来

注意:以上代码未经测试