我有一个像这样的文件
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;
}
答案 0 :(得分:6)
如果这是您正在制作的游戏,我会考虑更改输入文件格式的详细信息。如果使用现有的文件格式,则可以使用库来大大简化解析。
例如,这些相同的数据可以很容易地存储为XML,这将允许您使用XML解析器(例如TinyXML-2)来读取数据,并且可能使文件的创建更简单,以及。它还可以更简单地添加更强大的格式化问题处理,例如额外的空格等。
答案 1 :(得分:1)
无法创建语法并使用lex / yacc等工具为您创建解析器(BOOST库也有解析器),您需要读取每个令牌(就像您现在所做的那样:file >> token
- - 我建议使用std::string
作为令牌,而不是char
数组),然后将令牌与预期的下一个令牌进行比较(如果它是其中一个固定的令牌,如 EntityName ,动画, {)然后将令牌的值分配给结构的适当部分。如果需要一个整数作为下一个值,则可以将token
替换为结构的适当成员。
注意:如果采用这种方法,请确保在每次提取操作时检查错误,而不是假设文件始终采用正确的格式
答案 2 :(得分:1)
如果你有一个固定的文件格式,你不希望改变,那么你可以做readline,然后是if / else。否则为这种格式编写解析器非常简单,并提供更大的灵活性。下面是使用AX解析器生成器的示例。
一些假设:您没有指定名称是什么,我在此示例中使用标识符规则(axe::r_ident
),您可以将其更改为适合您需要的任何名称。我还假设您不关心空格,制表符,行尾,因此您可以使用axe::r_skip
规则来跳过它们。我假设你使用的数字是十进制的。
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());
}