跳过输入流值

时间:2014-02-25 13:33:36

标签: c++ istream

是否有任何简单的机制可以跳转到具有C ++输入流的下一个空格(如ifstream)?

我知道如果我知道要跳过多少个字符或预期的分隔符,我可以使用ignore。但IMO在ignore通常只读取下一个空格而不提供任何其他参数时使用operator>>是很难看的。我也可以使用假人,但这只会让事情变得更糟。

实施例

auto importantInfo1 = 0;
auto importantInfo2 = 0;
auto someDummy = 0; // This is ugly and doesn't clearly express the intent

file >> importantInfo1 >> someDummy >> importantInfo2;

同样在某些情况下,如果我需要在“skip”-case中处理不同的数据类型,我将需要多个虚拟对象。

我会想象这样的事情:

file >> importantInfo1;
file.skip<int>(1);
file >> importantInfo2;

或者甚至更好:

auto importantInfo1 = 0;
auto importantInfo2 = 0;

file >> importantInfo1 >> skip<int> >> importantInfo2;

我认为这样的解决方案也比在不需要时实际解析和存储值更好。

可能的解决方案

使用提供的答案制作此解决方案。它与接受的答案基本相同,但它不需要临时的。相反,它跳过第一个空格,然后跳过除空格之外的任何字符,直到再次到达空格。该解决方案可以使用2个while循环,但不需要知道提取的类型。我不是说这是一个高性能的解决方案或任何花哨的东西,但它使得生成的代码更短,更清晰,更具表现力。

template<typename CharT, typename Traits>
inline std::basic_istream<CharT, Traits>& skip(std::basic_istream<CharT, Traits>& stream)
{
    while (stream && std::isspace(stream.peek())) stream.ignore();
    while (stream && !std::isspace(stream.peek())) stream.ignore();
    return stream;
}

3 个答案:

答案 0 :(得分:1)

编写自己的忽略

#include <locale>
#include <iostream>

template< typename E, typename Traits, typename Pred >
std::basic_istream< E, Traits >& ignore_until( std::basic_istream< E, Traits >& in, Pred end )
{
    std::basic_istream< E, Traits >::sentry ok( in );
    if( ok )
    {
        std::ios_base::iostate state = std::ios_base::goodbit;
        try
        {
            for( Traits::int_type m = in.rdbuf()->sgetc(); ; m = in.rdbuf()->snextc() )
            {
                if( Traits::eq_int_type( m, Traits::eof() ) )
                {
                    state |= std::ios_base::eofbit;
                    break;
                }
                const E c = Traits::to_char_type( m );
                if( end( c ) )
                    break;
            }
        }
        catch( ... )
        {
            state |= std::ios_base::badbit;
            if( in.exceptions() & std::ios_base::badbit )
                throw;
        }
        in.setstate( state );
    }
    return in;
}

int main()
{
    using namespace std;
    locale loc = cin.getloc();
    for( int i; ignore_until( cin, [&loc]( char c ) { return std::isspace(c,loc); } ) >> i; )
        cout << i << endl;
}

答案 1 :(得分:1)

我认为你的想法是让操纵者跳过数据是正确的方法。

跳过'琐碎'的数据:

#include <sstream>

template<typename T, typename Char, typename Traits>
inline std::basic_istream<Char, Traits>& skip(std::basic_istream<Char, Traits>& stream) {
    T unused;
    return stream >> unused;
}

int main()
{
    std::istringstream in("1 666 2 ");
    int a;
    int b;
    in >> a >> skip<int> >> b;
    std::cout << a << b << '\n';
}

如果数据变得更复杂并且构造/流变得昂贵,则必须提供专门的重载并通过char解析char以跳过它。

答案 2 :(得分:0)

如果您想在上一个示例中使用类似跳过的内容,那么您可以创建一个重载运算符&gt;&gt;的Skip类。你需要这样的东西:

class Skip {
    friend istream& operator>> (istream &in, Skip &skip);
};

istream& operator>> (istream &in, Skip &skip) {
    // I'm not sure why you are parameterizing skip, but this is where
    // you would do whatever handles that
}