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
        }
    }
}

ただし、次の例に示すように、先頭と末尾の空白の行を削除することをお勧めします: C++ で std::string からスペースを削除する

于 2012-11-09T07:46:52.163 に答える
3

これが単なる用途の 1 つである場合、あなたのような行指向の入力の場合、最も簡単な解決策は、今読んだ行からコメントを削除することです。

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

より一般的な解決策は、次のようなフィルタリング streambuf を使用することです。

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 に答える