如何使用 块 C++ 解析文件
Posted
技术标签:
【中文标题】如何使用 块 C++ 解析文件【英文标题】:How do I parse a file with block C++如何使用 块 C++ 解析文件 【发布时间】:2012-05-24 13:54:06 【问题描述】:我有一个这样的文件
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;
【问题讨论】:
这是我正在制作的游戏。我需要从文本文件中收集数据并创建动画精灵。 你需要使用这种文件格式吗? 不,不是真的..但是我想让解析器读取块中的代码将是可扩展的.. 【参考方案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());
【讨论】:
在没有解释的情况下,通常被认为是不礼貌的投反对票【参考方案2】:无需创建语法并使用 lex/yacc 等工具为您创建解析器(BOOST 库也有解析器),您需要读取每个标记(就像您现在所做的那样:file >> token
-- I建议使用 std::string
作为令牌,而不是 char
数组),然后将令牌与预期的下一个令牌进行比较(如果它是固定令牌之一,例如 EntityName、Animation , ) 然后将标记的值分配给结构的适当部分。如果您需要一个整数作为下一个值,您可以将token
替换为结构的相应成员。
注意:如果您采用这种方法,请确保在每次提取操作时检查错误,而不是假设文件的格式始终正确
【讨论】:
【参考方案3】:如果这是针对您正在制作的游戏,我会考虑更改输入文件格式的详细信息。如果您使用现有的文件格式,则可以使用库来显着简化解析。
例如,同样的数据可以很容易地存储为 XML,这将允许您使用 XML 解析器(例如 TinyXML-2)来读取数据,并且可能还会简化文件的创建。它还可以更简单地添加更强大的格式问题处理,例如额外的空格等。
【讨论】:
你能建议我一些指向 c++ xml 解析器库的链接吗? @JeffreyChen:他把你链接到一个。还有these @JeffreyChen Nicol 的链接很棒 - 如果您只有简单的要求,TinyXML-2 非常好,鉴于您要编写自己的解析器,我猜是这样。在这种情况下,它超轻量级且易于使用... 有趣 - 为什么要投反对票? 在固执地尝试自己进行解析之后变得复杂并决定使用 tinyxml2 .. 很好用!!以上是关于如何使用 块 C++ 解析文件的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Linux 和 Windows 计算机上使用代码块开发 C++ 项目?
如何使用 C++ 解析带有 ParameterName 和 ParameterValue 的 XML