繁体   English   中英

如何在C ++中从istream干净地提取以字符串分隔的字符串

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM