[英]How to cleanly extract a string delimited string from an istream in c++
我正在尝试从istream中提取一个字符串 ,并使用字符串作为定界符 ,但我还没有在istream中发现任何行为接近于find()
或substr()
这样的字符串操作。
这是istream内容的示例: delim_oneFUUBARdelim_two
,我的目标是以尽可能少的变通办法将FUUBAR
转换为字符串。
我当前的解决方案是使用此解决方案将所有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)
...
这种表示法似乎有些骇人听闻,但Standard Library的std::quoted()
已有先例。
您可以在此处查看运行的代码。
标准流配备了可以进行分类的语言环境,即std::ctype<>
构面。 当下一个可用字符中没有某种分类时,我们可以使用此方面ignore()
流中的字符。 这是一个工作示例:
#include <iostream>
#include <sstream>
using mask = std::ctype_base::mask;
template<mask m>
void scan_classification(std::istream& is)
{
auto& ctype = std::use_facet<std::ctype<char>>(is.getloc());
while (is.peek() != std::char_traits<char>::eof() && !ctype.is(m, is.peek()))
is.ignore();
}
int main()
{
std::istringstream iss("some_string_delimiter3.1415another_string");
double d;
scan_classification<std::ctype_base::digit>(iss);
if (iss >> d)
std::cout << std::to_string(d); // "3.1415"
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.