std :: getline是读取指定分隔符不存在的行吗?

时间:2016-06-06 17:08:06

标签: c++ ifstream

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

{ 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 ...我是对的?错误在哪里?

2 个答案:

答案 0 :(得分:6)

while条件并不像您期望的那样有效:getline()会成功读取,直到达到&#39; {&#39;或者如果不是文件的末尾。

那么这里会发生什么?

  • 当您显示Object3时,您在流中的排名是在结束'}'之后。
  • getline()条件中的while会将所有剩余的文件读入content,因为它遇到没有'{'。因为它可以成功读取某些内容,所以条件评估为true。
  • getline()块中的while无法读取任何内容,因此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

答案 1 :(得分:1)

std::getline读取字符,直到分隔符(使用它)或直到流的结尾。只有在没有消耗字符时才会在流上设置failbit(在空/无效流上调用)。

因此,只有当流为空时,你的循环才会终止。

Streams界面只允许查看下一个字符,没有办法扫描输入,如果存在特定字符则执行读取。

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