我正在尝试从一个带有字符串作为分隔符的istream中提取一个字符串,但我还没有发现任何行为接近于的字符串操作istreams 中的 find()
或 substr()
。
这是一个 istream 内容示例:
delim_oneFUUBARdelim_two
我的目标是使用尽可能少的解决方法将 FUUBAR
变成一个字符串。
我目前的解决方案是使用 this 将所有 istream 内容复制到一个字符串中它的解决方案,然后使用字符串操作提取。有没有一种方法可以避免这种不必要的复制,并且只根据需要从 istream 中读取尽可能多的内容,以保留分隔字符串之后的所有内容,以防以类似的方式找到更多内容?
最佳答案
您可以轻松地创建一个将使用预期的分隔符或定界符的类型:
struct Text
{
std::string t_;
};
std::istream& operator>>(std::istream& is, Text& t)
{
is >> std::skipws;
for (char c: t.t_)
{
if (is.peek() != c)
{
is.setstate(std::ios::failbit);
break;
}
is.get(); // throw away known-matching char
}
return is;
}
在 ideone 上查看实际效果
当先前的流提取自然停止而不消耗定界符时(例如 int
提取后跟一个不以数字开头的定界符),这通常是这种情况,除非先前的提取是一个std::string
.单字符定界符可以指定给getline,但是假设你的定界符是"</block>"
并且流包含 "<black>metalic</black></block>42"
- 你想要提取一些东西 "<black>metallic</black>
"变成 string
,扔掉 "</block>"
定界符,留下 "42
"在流中:
struct Until_Delim {
Until_Delim(std::string& s, std::string delim) : s_(s), delim_(delim) { }
std::string& s_;
std::string delim_;
};
std::istream& operator>>(std::istream& is, const Until_Delim& ud)
{
std::istream::sentry sentry(is);
size_t in_delim = 0;
for (char c = is.get(); is; c = is.get())
{
if (c == ud.delim_[in_delim])
{
if (++in_delim == ud.delim_.size())
break;
continue;
}
if (in_delim) // was part-way into delimiter match...
{
ud.s_.append(ud.delim_, 0, in_delim);
in_delim = 0;
}
ud.s_ += c;
}
// may need to trim trailing whitespace...
if (is.flags() & std::ios_base::skipws)
while (!ud.s_.empty() && std::isspace(ud.s_.back()))
ud.s_.pop_back();
return is;
}
这可以用作:
string a_string;
if (some_stream >> Until_Delim(a_string, "</block>") >> whatevers_after)
...
这个表示法可能看起来有点老套,但在标准库的 std::quoted()
中有先例。 .
可以看到代码运行here .
关于c++ - 如何从 C++ 中的 istream 中干净地提取字符串分隔字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22692336/