简体   繁体   English

如何用{}块C ++解析文件

[英]How do I parse a file with {} block C++

I have a file like this 我有这样的文件

EntityName Jaws
{
  Animation WALK
  {
    NumberOfFrames 9
    DirectionOfSprite L
    DirectionGenerate LR
    FPS 9
  }

  Animation IDLE
  {
    NumberOfFrames 6
    DirectionOfSprite L
    DirectionGenerate LR
    FPS 9
  }
  .......
  .......
}

How do I parse this file in this struct 如何在此结构中解析此文件

struct AnimationData
{
  string animationName;
  int noOfFrames;
  eAnimationDataDirection direction;
  int FPS;
};

struct EntityAnimationData
{
  string entityName;
  vector<AnimationData> animationData;

  string getSpriteResourceName(AnimationData animationData, int frameNumber);
};

I want to store this data into the struct. 我想将这些数据存储到结构中。 How do I go about to get a clean solution? 我该如何获得一个干净的解决方案? I've read the basic reading of a file. 我已经阅读了文件的基本阅读材料。

This is what I've tried 这就是我尝试过的

EntityAnimationData parseAnimationData(const char* filename)
{
  EntityAnimationData data;
  ifstream file;
  file.open(filename);
  char output[128];
  string op;
  if (file.is_open())
  {
    while (!file.eof())
    {
      file >> output;
      if(strcmp(parameter,AD_ENTITY_NAME.c_str())==0)
      {
        file >> output;
        data.entityName = output;
        cout<<data.entityName<<endl;
        do
        {
          file >> output;
          cout<<output<<endl;
        }while(strcmp(output,"}")!=0);
      }
    }
  }
  file.close();
  return data;
}

If this is for a game you're making, I would consider changing the input file format details. 如果这是你正在制作的游戏,我会考虑更改输入文件格式的详细信息。 If you use an existing file format, you could use a library to dramatically simplify parsing. 如果使用现有文件格式,则可以使用库来大大简化解析。

For example, this same data could easily be stored as XML, which would allow you to use an XML parser (such as TinyXML-2 ) to read the data, and probably make creation of the file simpler, as well. 例如,这些相同的数据可以很容易地存储为XML,这允许您使用XML解析器(例如TinyXML-2 )来读取数据,并且可能使文件的创建更简单。 It also would make it simpler to add more robust handling of formatting issues, such as extra whitespace, etc. 它还可以更简单地添加更强大的格式问题处理,例如额外的空格等。

Sans of creating a grammar and using tools like lex/yacc to create a parser for you (the BOOST library has a parser too), you need to read each token (like you are doing now: file >> token -- I would recommend using std::string for the token, not a char array), then compare the token to the expected next token (if it's one of the fixed ones, like EntityName , Animation , { ) then assign the value of the token to the appropriate part of the structure. 无法创建语法并使用lex / yacc等工具为您创建解析器(BOOST库也有解析器),您需要读取每个令牌(就像您现在正在做的那样: file >> token - 我建议使用std::string作为令牌,而不是char数组),然后将令牌与预期的下一个令牌(如果它是固定的令牌之一,如EntityNameAnimation{ )进行比较,然后将令牌的值分配给相应的部分结构。 If you need an integer as the next value, you can replace token with the apropriate member of the structure. 如果需要一个整数作为下一个值,则可以使用结构的适当成员替换token

Note : If you take this approach, make sure you check for errors at each extraction operation, instead of assuming that the file will always be in the correct format 注意 :如果采用这种方法,请确保在每次提取操作时检查错误,而不是假设文件的格式始终正确

If you have a fixed file format, which you don't expect to change then you can do readline followed by if/else. 如果你有一个固定的文件格式,你不希望改变,那么你可以做readline,然后是if / else。 Otherwise writing a parser for this format is pretty simple and provides more flexibility. 否则为这种格式编写解析器非常简单,并提供更大的灵活性。 Below is an example of using AXE parser generator. 下面是使用AX解析器生成器的示例。

Some assumptions: you didn't specify what the names are, I'm using identifier rule ( axe::r_ident ) in this example, you may change it to whatever suits your needs. 一些假设:您没有指定名称是什么,我在此示例中使用标识符规则( axe::r_ident ),您可以将其更改为适合您需要的名称。 I also assume you don't care about spaces, tabs, line ends, so you can use an axe::r_skip rule to skip them all. 我还假设你不关心空格,制表符,行尾,所以你可以使用axe::r_skip规则来跳过它们。 I assume the numbers you use are decimal. 我假设你使用的数字是十进制的。

template<class I>
EntityAnimationData parse(I begin, I end)
{
    EntityAnimationData data;
    AnimationData ad; // temporary

    auto direction = axe::r_lit("LR") | "RL" | 'L' | 'R';

    auto animation_data = "Animation" & axe::r_ident() >> ad.animationName 
        & '{' 
        & "NumberOfFrames" & axe::r_decimal(ad.noOfFrames)
        & "DirectionOfSprite" & direction >> axe::e_ref([&](I i1, I i2)
        {
           std::string dir(i1, i2); // this will be "LR" or "RL" or 'L' or 'R'
           // ad.direction = ...
        })
        & "DirectionGenerate" & direction  >> axe::e_ref([&](I i1, I i2)
        {
           std::string dir(i1, i2); // this will be "LR" or "RL" or 'L' or 'R'
           // ad.direction = ...
        })
        & "FPS" & axe::r_decimal(ad.FPS)
        & '}';

    auto entity_data = axe::r_lit("EntityName") & axe::r_ident() >> data.entityName 
        & '{' 
        & *(animation_data >> axe::e_ref([&](...) { data.animationData.push_back(ad); }))
        & '}'
        & axe::r_end();
    // create a skip rule
    auto data_skip_spaces = axe::r_skip(entity_data, " \t\n");
    auto match = data_skip_spaces(begin, end);
    if(!match.matched)
        throw "format error";

    return data;
}

void foo()
{
   std::string text = "EntityName Jaws\n{\n  Animation WALK\n  {\n    NumberOfFrames 9 ...";
   EntityAnimationData data = parse(text.begin(), text.end());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM