6

このプログラムでは、シェル スクリプトでデータ ファイルのフィールド セパレータのみを使用しました。しかし、標準ライブラリ関数 ifstream() を使用してデータ ファイルから読み込もうとしています。唯一の問題は、そのようにデータを取得していることです

A:KT5:14:エグゼクティブ デスク:

これはハッシュ テーブル用であり、データ構造とトランザクション タイプの行で値を区切る必要があります。私はウェブを見回してきましたが、フィールドセパレーターについてはあまり見つけていませんでした.私が見つけたものはかなり混乱していました.

問題は、ifstream 関数を使用してフィールド セパレータを設定する方法はありますか、それとも別の標準ライブラリ i/o 関数を使用する必要があるかということです。

ありがとう。

4

2 に答える 2

6

@Steve Townsend はすでに 1 つの可能性を指摘しています。operator>>の代わりに使用したい場合はstd::getline、それも可能です。Anistreamは常に空白をセパレータとして扱います。各ストリームには関連付けられたロケールがあり、各ロケールにはctypeファセットが含まれています。そのctypeファセットは、 がistreamどの入力文字が空白であるかを判断するために使用するものです。

あなたの場合、ストリームが改行とコロンのみを「空白」(つまり、セパレータ) として扱うようにしたいようですが、実際のスペース文字はセパレータではなく「通常の」文字として扱われます。

これを行うには、次のように ctype ファセットを作成できます。

struct field_reader: std::ctype<char> {

    field_reader(): std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table() {
        static std::vector<std::ctype_base::mask> 
            rc(table_size, std::ctype_base::mask());

        rc['\n'] = std::ctype_base::space;
        rc[':'] = std::ctype_base::space;
        return &rc[0];
    }
};

これを使用するには、このファセットを使用してストリームにロケールを「吹き込む」必要があります。

int main() {
    std::stringstream input("A:KT5:14:executive desk:");

    // have the stream use our ctype facet:
    input.imbue(std::locale(std::locale(), new field_reader()));

    // copy fields from the stream to standard output, one per line:
    std::copy(std::istream_iterator<std::string>(input), 
              std::istream_iterator<std::string>(),
              std::ostream_iterator<std::string>(std::cout, "\n"));
    return 0;
}

ただし、これにはいくつかの欠点があることを最初に認めます。まず第一に、ロケールとファセットは一般的に文書化されていないため、ほとんどのC++ プログラマーはこれを理解するのがかなり難しいと感じる可能性があります (特に、すべての実際の作業が「隠れて」行われる場合)。

もう 1 つの可能性は、Boost Tokenizerを使用することです。正直なところ、これを使用するにはもう少し手間がかかります。文字列を読み取り、それを個別に分割するなどの作業が必要になります。同時に、それは十分に文書化されており、かなり広く知られており、そのようなことを行う方法についての人々の先入観に十分に適合しているため、かなりの数の人々は、余分な複雑さにもかかわらず、おそらく従うのが簡単になるでしょう.

于 2010-11-16T19:13:29.737 に答える
5

getlineは、区切り文字を指定するオプションを提供します。string次に、ストリームからの入力を、次で区切られたシーケンスとして読み取ることができます_Delim

template<class CharType, class Traits, class Allocator>
   basic_istream< CharType, Traits >& getline(
       basic_istream< CharType, Traits >& _Istr,
       basic_string< CharType, Traits, Allocator >& _Str,
       CharType _Delim
   );

これが一様に構造化されたデータである場合、それを含む構造体を定義operator>>し、オペレーター コード内部の上記の関数を使用して、ストリームから各インスタンスをロードするように実装すると便利な場合があります。

複数の行を処理する必要がある場合 (つまり、改行がレコード区切り記号で、 : フィールド区切り記号)、各行を順番にstringstreamusingbasic_istream::getlineにロードし、次に示すように行をフィールドに後処理します。

于 2010-11-16T18:40:01.523 に答える