2

私はこのようなファイルを持っています

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

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

この構造体でこのファイルを解析するにはどうすればよいですか

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

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

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

このデータを構造体に保存したいと思います。どうすればクリーンなソリューションを入手できますか?ファイルの基本的な読み方を読みました。

これは私が試したことです

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

3 に答える 3

6

これがあなたが作っているゲームのためのものであるならば、私は入力ファイルフォーマットの詳細を変更することを検討するでしょう。既存のファイル形式を使用する場合は、ライブラリを使用して解析を大幅に簡素化できます。

たとえば、これと同じデータをXMLとして簡単に保存できます。これにより、XMLパーサー(TinyXML-2など)を使用してデータを読み取り、ファイルの作成も簡単になります。また、余分な空白などのフォーマットの問題のより堅牢な処理を追加することも簡単になります。

于 2012-05-16T23:34:35.287 に答える
1

文法を作成し、lex / yaccなどのツールを使用してパーサーを作成する必要はありません(BOOSTライブラリにもパーサーがあります)。各トークンを読み取る必要があります(現在行っているように:file >> token-std::stringトークンに使用することをお勧めします、char配列ではなく)、トークンを予想される次のトークンと比較し(EntityNameAnimation{などの固定トークンの場合)、トークンの値を構造の適切な部分に割り当てます。次の値として整数が必要な場合tokenは、構造体の適切なメンバーに置き換えることができます。

:このアプローチを採用する場合は、ファイルが常に正しい形式であると想定するのではなく、各抽出操作でエラーをチェックするようにしてください。

于 2012-05-16T23:38:55.720 に答える
1

変更する予定のない固定ファイル形式がある場合は、readlineの後にif/elseを実行できます。それ以外の場合、この形式のパーサーを作成するのは非常に簡単で、柔軟性が高くなります。以下は、AXパーサジェネレータの使用例です。

いくつかの仮定:名前が何であるかを指定しなかったaxe::r_ident、この例では識別子ルール()を使用しているので、必要に応じて変更することができます。また、スペース、タブ、行末は気にしないと思いますので、axe::r_skipルールを使用してそれらをすべてスキップできます。使用する数字は10進数だと思います。

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());
}
于 2012-05-21T17:45:48.140 に答える