【问题标题】:C : Using substr to parse a text fileC : 使用 substr 解析文本文件
【发布时间】:2013-04-27 16:26:57
【问题描述】:

我只需要一点文件解析方面的帮助。我们必须解析一个每行有 6 个字符串条目的文件,格式为:

“字符串 1”、“字符串 2”、“字符串 3”、“字符串 4”、“字符串 5”、“字符串 6”

我的导师最近给了我们一小段代码作为“提示”,我应该使用它。不幸的是,我不知道如何让它工作。这是我的文件解析函数。

void parseData(ifstream &myFile, Book bookPtr[])
{

    string bookInfo;
    int start, end;
    string bookData[6];

    getline(myFile, bookInfo);
    start = -2;

    myFile.open("Book List.txt");

    for (int j = 0; j < 6; j++)
    {
        start += 3;
        end = bookInfo.find('"', start);
        bookData[j] = bookInfo.substr(start, end-start);
        start = end;
    }



}

所以我试图将 6 个字符串读入一个字符串数组。有人可以帮我完成整个过程吗?

【问题讨论】:

  • 你的导师给了你这段代码。我建议你改变课程,因为这是一种非常糟糕的方式。
  • 我同意詹姆斯的观点。我已经包含了可以说是解析带引号的字符串多行文件的“更好”方法。它并不完美,但它比你的教练给你的“提示”要好得多(这是一个“提示”可以肯定,但与他们的熟练程度有关,而不是解决这个具体问题)。

标签: c++ file parsing substr


【解决方案1】:
start = -2;
for (int j = 0; j < 6; j++)
{
    start += 3;
    end = bookInfo.find('"', start);
    bookData[j] = bookInfo.substr(start, end-start);
    start = end;
}

所以", " 是四个字符。前导闭引号在开闭引号后面 3 个字符。

在循环的入口处,start 指向最后一个结束引号。 (在第一次进入循环时,它被伪装成-2 指向虚构的“-1th”元素的右引号。)

所以我们从最后一个结束报价前进到下面的开始报价:

    start += 3;

然后我们使用 std::string::find 来查找结束引号:

    end = bookInfo.find('"', start);

偏移量告诉它忽略直到并包括该位置的所有字符。

然后我们有两个引号位置,start..end,所以我们使用substr 来提取字符串:

    bookData[j] = bookInfo.substr(start, end-start);

然后我们将下一个循环的 start 更新为最后一个结束引号:

    start = end

【讨论】:

    【解决方案2】:

    为了您自己,请创建一个最小的示例。这以您作为示例给出的行的字符串开头,并以数组中的不同部分结尾。暂时不要从文件中加载, getline() 似乎对您有用,还是?然后,不要在函数开头声明您可能想要使用的每个变量。这不是古老的 C,您只需要这样做或引入额外的 {} 块。还有一件事很奇怪,那就是Book bookPtr[]。这确实只是一个Book* bookPtr,即您没有将数组传递给函数,而只是传递一个指针。不要相信这种误导性的语法,这是一个谎言!无论如何,您似乎并没有使用指向未知类型对象的指针。

    关于将行拆分为字符串,一种方法是定位双引号对。中间的一切都是弦之一,没有的一切都是无关紧要的。 string 类有一个 find() 函数,它可以选择一个起始位置。起始位置总是比先前找到的位置晚一个。

    您上面的代码似乎假设只有一个双引号、一个逗号、一个空格和另一个分隔两个字符串的双引号。这不是 100% 清楚的,我也会准备好处理多个空格或根本没有空格。另外,逗号有保证吗?双引号有保证吗?无论如何,保持简单。除非您对输入有更好的规范,否则请假设只有引号之间的部分有所不同。

    那么,究竟什么有效,什么无效?您需要提出更具体的问题并提供更详细的信息。上面的代码本身看起来并没有损坏,尽管有些地方有点不对劲。例如,您通常不会将 ifstreams 传递给函数,而是使用 istream 基类。在您的情况下,您从该文件中读取一行,然后使用相同的 fstream 对象打开另一个文件,这对我来说没有意义,因为在那之后您不再使用它。如果您只在本地需要该流,您可以在那里创建并打开它(当然要处理错误!)并仅将文件名作为参数传递。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-10
      • 2010-10-25
      • 1970-01-01
      • 2015-01-07
      • 1970-01-01
      • 1970-01-01
      • 2013-11-28
      • 1970-01-01
      相关资源
      最近更新 更多