1

所以我在这个网站上看到了很多关于从 C++ 中读取文本文件的解决方案和教程,但还没有找到解决我问题的方法。我是 C++ 的新手,所以我认为我无法拼凑一些文档来理解这一切。

我要做的是读取文本文件编号,同时忽略文件中由“#”表示的注释。所以一个示例文件看起来像:

#here is my comment
20 30 40 50
#this is my last comment
60 70 80 90

当没有任何评论时,我的代码可以很好地读取数字,但我不理解如何很好地解析流以忽略评论。它现在是一种黑客解决方案。

/////////////////////// Read the file ///////////////////////
std::string line;
if (input_file.is_open())
{
    //While we can still read the file
    while (std::getline(input_file, line))
    {
        std::istringstream iss(line);
        float num; // The number in the line

        //while the iss is a number 
        while ((iss >> num))
        {
            //look at the number
        }
    }
}

else
{
    std::cout << "Unable to open file";
}
/////////////////////// done reading file /////////////////

有没有办法可以将评论处理与此解决方案结合起来,或者我是否需要不同的方法?任何建议都会很棒,谢谢。

4

3 回答 3

5

如果您的文件#始终包含在第一列中,那么只需测试,如果该行以#这样的开头:

while (std::getline(input_file, line))
{
    if (line[0] != "#" )
    {
        std::istringstream iss(line);
        float num; // The number in the line

        //while the iss is a number 
        while ((iss >> num))
        {
            //look at the number
        }
    }
}

修剪前导和尾随空格的行是明智的,例如此处所示:Remove spaces from std::string in C++

于 2012-11-09T07:46:52.163 回答
3

如果这只是一种用途,对于像您这样的面向行的输入,最简单的解决方案就是从您刚刚阅读的行中删除注释:

line.erase( std::find( line.begin(), line.end(), '#' ), line.end() );

更通用的解决方案是使用过滤流缓冲区,例如:

class FilterCommentsStreambuf : public std::streambuf
{
    std::istream& myOwner;
    std::streambuf* mySource;
    char myCommentChar;
    char myBuffer;

protected:
    int underflow()
    {
        int const eof = std::traits_type::eof();
        int results = mySource->sbumpc();
        if ( results == myCommentChar ) {
            while ( results != eof && results != '\n') {
                results = mySource->sbumpc(0;
            }
        }
        if ( results != eof ) {
            myBuffer = results;
            setg( &myBuffer, &myBuffer, &myBuffer + 1 );
        }
        return results;
    }

public:
    FilterCommentsStreambuf( std::istream& source,
                             char comment = '#' )
        : myOwner( source )
        , mySource( source.rdbuf() )
        , myCommentChar( comment )
    {
        myOwner.rdbuf( this );
    }
    ~FilterCommentsStreambuf()
    {
        myOwner.rdbuf( mySource );
    }
};

在这种情况下,您甚至可以放弃getline

FilterCommentsStreambuf filter( input_file );
double num;
while ( input_file >> num || !input_file.eof() ) {
    if ( ! input_file ) {
        //  Formatting error, output error message, clear the
        //  error, and resynchronize the input---probably by
        //  ignore'ing until end of line.
    } else {
        //  Do something with the number...
    }
}

(在这种情况下,我发现跟踪 . 中的行号也很有用FilterCommentsStreambuf。这样你就有了错误消息。)

于 2012-11-09T08:39:47.607 回答
1

“读取一行并将其解析为字符串”的替代方法可以将流本身用作传入缓冲区:

while(input_file)
{
    int n = 0;

    char c; 
    input_file >> c; // will skip spaces ad read the first non-blank

    if(c == '#')
    {
        while(c!='\n' && input_file) input_file.get(c);
        continue; //may be not soooo beautiful, but does not introduce useless dynamic memory
    }

    //c is part of something else but comment, so give it back to parse it as number
    input_file.unget(); //< this is what all the fuss is about!
    if(input_file >> n)
    { 
        // look at the nunber
        continue;
    }

    // something else, but not an integer is there ....
    // if you cannot recover the lopop will exit 
}
于 2012-11-09T08:26:07.673 回答