高级文件和字符串操作

时间:2015-04-23 00:17:52

标签: c++ string file directx fstream

所以我正在研究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函数(仅用于组织我的代码并跳转到某一行并检索该行数据并放入一个字符串中,字符串的剪切和修改需要返回到main函数中):

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

老实说,这个ReadLine功能,我不知道我在做什么。我只是制作了一些框架来向您展示我希望如何组织代码。

再一次,谢谢。

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

我就是这样做的:

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也不是必需的。最后,如果您的文件被恰当地命名,T:也可能是不必要的,例如"test.texture"。这样你就知道你正在阅读的文件是纹理。

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