【问题标题】:std::getline is reading line where specified delimiter is not present?std::getline 正在读取不存在指定分隔符的行?
【发布时间】:2025-12-27 05:25:07
【问题描述】:

我想从以下字符串的数组(存储在文件中)打印控制台中的每个对象:

{ beforechars [{Object1},{Object2},{Object3}] afterchars }

我是这样做的:

std::ifstream is("content.txt");
std::getline(is, content, '[');
while (std::getline(is,content,'{')) {
    std::getline(is,content,'}');
    std::cout << content << std::endl;
}
in.close();

但是我得到了这个输出:

 Object1
 Object2
 Object3
] afterchars }

我的理解是,在Object3 迭代之后,ifstream 应该有 "}] afterchars }" 而 while 的守卫不应该是真的,因为没有任何 '{' char... 我说的对吗?哪里错了?

【问题讨论】:

  • std::getline 也提取了分隔符,这就是为什么没有}
  • @LogicStuff 是的,我明白了。我不明白的是为什么控制台打印最后一行如果有任何'{'字符,但正如克里斯托夫所说,getline 如果找不到分隔符,显然会打印整个文件......谢谢!

标签: c++ ifstream


【解决方案1】:

while 条件没有按预期工作:getline() 将成功读取,直到它到达一个 '{' 或者如果没有到达文件末尾。

那么这里发生了什么?

  • 当您显示Object3 时,您在信息流中的位置在关闭'}' 之后。
  • while 条件中的getline() 会将文件的所有剩余部分读入content,因为它没有遇到'{'。由于它可以成功读取某些内容,因此条件被评估为真。
  • while 块中的getline() 然后无法读取任何内容,因此content 将保持不变。然后流处于失败状态。在您清除此状态之前,任何后续操作都不会成功。但是现在您的代码中没有任何可见的事情发生。
  • 显示最后一个结果后,下一个循环条件将失败。

简单的解决方法:

一个非常简单的解决方法是在查找'{' 之前保留流中的当前位置,如果找不到,请返回此位置。注意:从性能的角度来看,这种解析文件的方式不是很好,但是对于小文件来说还可以。

std::getline(is, content, '[');
auto pos = is.tellg();    // read current position
while (std::getline(is,content,'{') && !is.eof()) { 
    std::getline(is,content,'}');
    pos = is.tellg();     // update position before iterating again
    std::cout << content << std::endl;
}
is.seekg(pos);   // and get back to last position

这里的技巧是,如果没有找到'{',在getline() 之后,流还没有处于失败状态,但eof() 已经为真。然后我们可以结束循环并回到最后记录的位置。

Online demo

【讨论】:

  • 哦,我明白了...如果 getline 找不到指定的分隔符,有没有办法告诉它不要继续阅读?或者您对我该如何解决这个问题有任何想法?谢谢!
【解决方案2】:

std::getline 读取字符直到分隔符(使用它)或直到流结束。仅当没有消耗字符(在空/无效流上调用)时,它才会在流上设置故障位。

所以你的循环只会在流为空时终止。

Streams 接口只允许查看下一个字符,无法扫描输入并在存在特定字符时进行读取。

如果您需要随机访问字符,则需要读取字符串中的输入,然后对其进行解析(使用正则表达式或其他方式。)

【讨论】: