您将如何使用C或C ++阅读简单的文件格式?
例如,采用Wavefront .obj文件格式,示例:
# this is a box
o 1
v -0.5 -0.5 0.5
v -0.5 -0.5 -0.5
v -0.5 0.5 -0.5
v -0.5 0.5 0.5
v 0.5 -0.5 0.5
v 0.5 -0.5 -0.5
v 0.5 0.5 -0.5
v 0.5 0.5 0.5
usemtl Default
f 4 3 2 1
f 2 6 5 1
f 3 7 6 2
f 8 7 3 4
f 5 8 4 1
f 6 7 8 5
由于文件可能非常大,我使用operator []创建了一个中间类(FileBuffer)。它只在内存中有4096个字节的文件,并在需要时读取新的部分。 文件格式非常简单,但我不喜欢使用像flex / bison这样的东西。这只会使问题复杂化。
解释这种(某种)文件的正确方法是什么?目前我有很多嵌套for / while循环和许多计数器保持跟踪。还有很多switch / elseif语句。我如何才能使这段代码整体可维护和更加结构化?
感谢。
答案 0 :(得分:2)
如果是我,我会尽可能多地利用标准库:
struct Command { /* Abstract Base Class */ ... };
struct VCommand : Command { std::vector<double> dims; ... }
struct FCommand : Command { std::vector<int> vertexes; ... }
struct FootCommand : Command { enum {LEFT, RIGHT, IN, OUT} e; ... }
std::vector<Command*> commandList; // DANGER: raw pointers
void ParseInput(std::istream& in) {
// untested code:
std::string line;
while(getline(in, line)) {
std::stringstream lineStream(line);
std::string command;
lineStream >> command;
if(command == "v") {
std::istream_iterator<double>(lineStream) begin;
std::istream_iterator<double> end;
// Add the "v" command to the parse tree
commandList.push_back(new VCommand(begin, end));
} else if (command == "f") {
std::istream_iterator<int>(lineStream) begin;
std::istream_iterator<int> end;
// Add the "v" command to the parse tree
commandList.push_back(new FCommand(begin, end));
} else if (command == "quit") {
...
} else if (command == "put_your_left_foot_in") {
...
commandList.push_back(new FootCommand(LEFT, IN));
}
}
}
答案 1 :(得分:1)
如果我正确理解格式,则每行定义
特定类型的数据,类型由第一种确定
字。我首先定义一个抽象基类和
每种类型的行的类的具体实例; ID
在std::map<std::string,
LineParser*>
。
为了阅读文件,我可能会安装过滤streambuf 摆脱上游的评论和空行。然后 一个简单的循环可以解决这个问题:
std::string line;
while ( std::getline( filteredInput, line ) ) {
std::string keyword;
std::istringstream toParse( line );
toParse >> keyword;
std::map<std::string, LineParser*>::const_iterator
parser = registry.find( keyword );
if ( parser == registry.end() ) {
// Syntax error: unknown keyword...
} else {
parser->parse( toParse );
}
}
答案 2 :(得分:0)
我将从定义(或获取)文件语法/结构开始。
然后根据该语法为输入流构建解析器。