代码之家  ›  专栏  ›  技术社区  ›  Remy Lebeau

是否有一个标准选项可以丢弃std::istream中的NON空白字符,直到遇到空白为止?

c++
  •  0
  • Remy Lebeau  · 技术社区  · 3 年前

    我很确定答案是 No ,但我还是要问。

    标准 std::ws I/O操纵器丢弃 std::istream 直到遇到非空白字符。

    但是,有标准吗 有效率的 选择相反的做法-丢弃非空白字符,直到遇到空白字符?

    我知道 std::istream::ignore() 可以使用,但这需要指定最大计数和/或分隔符。但是,如果你不知道下一个空白字符是什么呢?可能是 ' ' '\t' '\n' 。计数可以是 std::numeric_limits<std::streamsize>::max() 读取到EOF,但没有指定多个分隔符或使用比较谓词的选项。

    我能想到的唯一可行的选择是使用 >> 提取运算符读取临时 std::string ,例如:

    int value;
    if (!(cin >> value))
    {
        cin.clear();
    
        string ignored;
        cin >> ignored;
    }
    

    但这有可能为即将被丢弃的数据分配内存。

    我希望有更像 nonws I/O操纵器,或 >> 的过载 std::ignore ,或类似的东西,例如:

    int value;
    if (!(cin >> value))
    {
        cin.clear();
    
        cin >> nonws;
        or:
        cin >> std::ignore;
        or:
        cin.ignore(numeric_limits<streamsize>::max(),
            [](unsigned char c){ return !iswspace(c); }
        );
    }
    

    显然,这些都不存在,但有没有其他类似的选项可以从 std::istream ,不分配动态内存,使用最大大小 char[] 缓冲区,或在上运行手动循环 istream::(peek|get) ?基本上,做任何事情 istream::ignore() 已经完成,但使用 iswspace() -比如检查分隔符?

    我主要考虑的是 >> 运算符未能提取(即数值),当前输入应被丢弃,但仅适用于 当前单词 ,不是一直到下一个换行符。


    额外的好处:有人提议将这样的东西纳入C++标准吗?

    0 回复  |  直到 3 年前
        1
  •  0
  •   Revolver_Ocelot    3 年前

    不,我怀疑是否有这样的选择,至少我不知道。然而,写操纵器自己做这样的事情很容易:

    #include <iostream>
    #include <string>
    #include <locale>
    
    std::istream& nows(std::istream& in)
    {
        const auto& ctype = std::use_facet<std::ctype<char>>(in.getloc());
    
        if (not in) return in;
    
        for (std::istream::int_type c = in.peek(); c != std::istream::traits_type::eof(); c = in.peek()) {
            if ( ctype.is(std::ctype_base::space, std::istream::traits_type::to_char_type(c)) )  
                break;
            in.get();
        }
        return in;
    }
    
    int main()
    {
        std::string input;
        std::cin >> nows;
        std::getline(std::cin, input);
        std::cout << input << '\n';
        std::cout << "----|----|" << std::endl;
    }
    

    将此代码模板化以使用的所有实例 basic_istream 留给读者练习。

    进料线后 123 4567 8 作为输入

         4567 8
    ----|----|
    

    作为输出。正如你所看到的, nows 操纵器消耗了所有非空白字符,直到遇到第一个空白为止。