高级文件和字符串操作

Advanced File and String Operations

本文关键字:操作 字符串 文件 高级      更新时间:2023-10-16

所以我正在DirectX 11程序中开发一个模型加载程序,我遇到了一个我认为独特的问题。所以我花了一些时间寻找解决方案,但没有成功。我的问题是,在我的文件中,有纹理路径和顶点列表,我希望能够挑选出某些部分,并删除一些。下面是我的无纹理三角形示例文件:

T:0$
(0, 5, 0)
(5, 0, 0)
(-5, 0, 0)

^这是旧的,看看下面的编辑^

让我解释一下这里发生了什么。首先,"T:___"是纹理的文件路径。我已将其设置为"0",因为我没有使用纹理。"T:0"之后的"$"是我的程序对文件路径结束和顶点开始的标记。

现在,这是我需要我的程序做的。

1.读取文件,直到达到字符"$"。然后擦除前两个字符("T:")和"$"(如果已添加)。最后将剩余的文本放入一个名为TextureData的字符串中。附言:不要从文件中删除"t:",只删除我的字符串(文件需要保持原样)。

2.将剩余的文本(顶点)放入一个名为VertexData的临时字符串中,然后可能删除括号。。?我很想知道如何做到这一点,但现在可能不使用它。

我希望我把自己和我的问题说得足够清楚。

提前谢谢。

---重要编辑--

我已经改变了我的格式一点,我看了一个.obj文件,并决定这将更容易做到。我的纹理和顶点文件现在看起来像这样:

T:0$
v 0 5 0
v 5 0 0
v -5 0 0

---编辑结束--

这里的代码是我的基础:

模型加载功能:

bool LoadTVF(string FP)
{
ifstream TVFReader;
TVFReader.open(FP);
if (TVFReader.is_open())
{
ReadLine(1);    // Function not fully working, need to improve
// Load vertices and texture into strings
TVFReader.close();
return true;
}
else
{
return false;
}
}

ReadLine函数(只是为了组织我的代码并跳到某一行,检索该行的数据并放入字符串中,字符串的剪切和修改需要回到主函数中):

string ReadLine(int character)
{
return lineData;    // I know this doesn't work, just don't know what to return?
}

老实说,使用这个ReadLine函数,我不知道自己在做什么。我只是在制作某种框架,向您展示我希望如何组织代码。

再次感谢。

我会这样做:

bool LoadTVF(string FP)
{
ifstream TVFReader;
TVFReader.open(FP);
if (TVFReader.is_open()) {
stringstream buffer;
buffer << TVFReader.rdbuf();
string texture_string = buffer.str();
texture_string = texture_string.substr(2, texture_string.length());
// Removes T:
texture_string.erase(texture_string.begin() + texture_string.find("$"));
// Removes the first occurrence of $
std::cout << texture_string;
/* This will print out:
* 0
* v 0 5 0
* v 5 0 0
* v -5 0 0
*/
TVFReader.close();
return true;
}
else
{
return false;
}
}

这不使用ReadLine函数,因为它一次加载整个字符串。由于我只是在一开始就处理这个字符串,所以我宁愿将解析和修剪逻辑放在一个地方。

如果必须逐行迭代,那么已经有一种使用getline:的方法可以做到这一点

bool LoadTVF(string FP)
{
ifstream TVFReader;
TVFReader.open(FP);
if (TVFReader.is_open()) {
string line;
while(getline(TVFReader, line))
{
// Do stuff with each line
}
TVFReader.close();
return true;
}
else
{
return false;
}
}

请注意,这些line中没有行尾字符。

编辑:根据OP的评论,以下是如何将解析后的文件拆分为单独的字符串:

bool LoadTVF(string FP)
{
ifstream TVFReader;
TVFReader.open(FP);
if (TVFReader.is_open()) {
string header;
getline(TVFReader, header);
header = header.substr(2, header.length());
// Removes T:
header.erase(header.begin() + header.find("$"));
// Removes the first occurrence of $
std::cout << header << std::endl;
// This should print 0, which is the string between T: and $
stringstream buffer;
string line;
while (getline(TVFReader, line))
{
line = line.substr(2, line.length());
// Removes the starting "v "
buffer << line << std::endl;
// We need the end-of-line here because its been stripped
}
string texture_string = buffer.str();
std::cout << texture_string;
/* This will print out:
* 0 5 0
* 5 0 0
* -5 0 0
*/
TVFReader.close();
return true;
}
else
{
return false;
}
}

我想在这里做几点笔记。如果您可以控制文件的结构方式,则不需要$字符来指示该行的末尾。事实上,有一条换行符应该足以说明这一点。此外,由于后面的每一行都表示矩阵中的一个向量,我认为v也没有必要。最后,如果文件的名称适当,比如"test.texture",那么T:也可能是不必要的。这样你就知道你正在读取的文件是一个纹理。

这将降低解析这些文件的复杂性,并且作为奖励,还可以减少这些文件的存储大小。

到目前为止,您似乎可以使用getline逐行读取文件,然后提取必要的信息:通过检查第一个字符来确定"行类型",然后根据类型获取带路径的子字符串或将行拆分为块并将其转换为浮点数。

稍后,当/如果您的文件格式变得更加复杂时,您可能需要编写一个完整的解析器,可能需要使用某种解析器生成器。