Получение строковых токенов / параметров при разборе

Я изо всех сил пытался найти способ в C ++ получить токены и параметры в моем собственном файле сценария, я могу сделать это в C # с помощью регулярных выражений и все, но мне нужно сделать это в C ++

Допустим, у меня есть этот файл сценария:

Name = Tywin Lanninster
Age = 35

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

Что мне нужно знать о том, как взаимодействовать через весь этот код и запускать между токенами?
Как получить значение имени, возрастное значение, а затем получить все данные в поведении, а также получить его значение? Это похоже на то, что я могу разобрать это, я придаю импульс, но Дух не то, что я ищу, я видел std::string имеет find_first_of функция, поэтому я ищу ответы.

Я нашел вопрос, подобный моему, от 2007 года, но приведенный код не является достаточным, поскольку он неполон, но я вижу, что это то, что я ищу: http://www.daniweb.com/software-development/cpp/threads/76797/simple-script-parser-how-to-

Пожалуйста, помогите мне!

Итак, я сделал это:

Это мой первый цикл загрузки для разбора:

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

Функция, которую я использую для получения токенов, позволяет получать такие вещи, как Age & название

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

Код, который я использую для получения строк внутри «

    bool Script::getString()
char letter;
std::string str;
std::cout << "Trying to get string from: " << text << std::endl;
for (int i = 0; i != 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;
}
}

Но я не знаю, как получить вещи внутри {}, так как они в разных строках, и я использую getline

1

Решение

Обновить:

Учитывая, что ваш формат файла немного сложнее, чем я думал, я сделал еще один снимок, используя этот раз. Действительно, это утомительное предприятие, чтобы заставить его работать с чем-то более сложным, чем тривиальные примеры из учебника, но с небольшой помощью записей в стеке потока мне удалось заставить что-то работать.

Здесь это идет:

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

}
}

Несколько моментов:

Для этого я использовал версию Boost 1.49.

Приведенный выше код работает с образцом, представленным в вопросе, если он хранится в файле (точно названном player.txt) , а также с двойными кавычками вокруг строк, которые должны быть значениями, а не ключевые слова, как, например, значение для название приписывать.

Я решил разделить грамматику на две части, чтобы вы могли повторно использовать и расширять раздел атрибутов. Кажется разумным предположение о том, куда вы направитесь дальше. Однако это означает, что поддержка сериализация будет сложно. В 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 должен быть класс, который вы определили, который содержит данные, которые вы проанализировали. Вы должны получить идею. Сейчас пожалуйста, попробуйте написать что-нибудь и вернуться, если вы застряли.

Замечания: вышеуказанный код не проверен.

0

Другие решения


По вопросам рекламы [email protected]