如何从字符串流中的同一位置读取两次

How to read from the same location in a stringstream twice?

本文关键字:读取 位置 两次 字符串      更新时间:2023-10-16

我有一个正在读取的stringstream实例。在从流中获取数据的某个时刻,我需要读取一个可能存在也可能不存在的标识符。逻辑是这样的:

std::string identifier;
sstr >> identifier;
if( identifier == "SomeKeyword" )
    //process the the rest of the string stream using method 1
else
   // back up to before we tried to read "identifier" and process the stream using method 2

如何实现上述逻辑?

使用流的tellg()seekg()方法,例如:

std::string identifier;
std::stringstream::pos_type pos = sstr.tellg();
sstr >> identifier;
if (identifier == "SomeKeyword")
{
    //process the rest of the string stream using method 1
}
else
{
    // back up to before we tried to read "identifier
    sstr.seekg(pos);
    // process the stream using method 2
}

您可以在获取标识符之前获取流中的get指针,并在标识符错误的情况下恢复位置:

std::string identifier;
std::stringstream::pos_type pos = sstr.tellg();
sstr >> identifier;
if( identifier == "SomeKeyword") {
    // process the the rest of the string stream using method 1
} else {
   sstr.clear();
   sstr.seekg(pos, sstr.beg);
   // process the stream using method 2
}

cplusplus.com上的tellg页面有一个非常好的例子。调用clear()的目的是确保即使上一次读取到达文件末尾,seekg也能工作。这仅适用于C++11之前的C++版本。如果您使用的是C++11或更新版本,seekg会自动清除EOF位,并且您不应在解决方案中包含带有clear()的行。感谢@metal指出这一点。

您可以直接检查stringstream的内容。这可能是一种比提取和回滚更清晰的方法,因为提取后不能保证你的stringstream状态。例如,如果您的字符串只包含一个单词,那么提取它就会设置ios_base::iostate::eofbit标志。

你可以像这样完成对stringstream内容的检查:

if(sstr.str().compare(0, identifier.length(), identifier) == 0) {
    sstr.ignore(identifier.length());
    // process the the rest of the string stream using method 1
} else {
    // process the stream using method 2
}

这样做的一个风险是,如果您依赖stringstream的提取运算符来消除前导空白,则在执行compare之前需要清除。这可以通过在if块之前使用命令sstr >> skipws;来完成。

虽然我确实认为这种方法更安全,但应该注意的是,如果"方法2"依赖于sstr中的前导空白,那么你应该使用其他答案之一(但你也应该重新考虑你对stringstream的使用,因为所有提取运算符都首先吃空白。)