3

私はこの答えを適応させようとしています

C ++で文字列をトークン化するにはどうすればよいですか?

ファイルからeofまでの読み取りを含む私の現在の文字列の問題に。

このソースファイルから:

Fix grammatical or spelling errors

Clarify meaning without changing it

Correct minor mistakes

トークン化されたすべての単語を含むベクトルを作成したいと思います。例:vector<string> allTheText[0] should be "Fix"

目的はわかりませんがistream_iterator<std::string> end;、元のポスターの回答にあったので含めました。

これまでのところ、私はこの機能しないコードを持っています:

vector<string> allTheText;
          stringstream strstr;
          istream_iterator<std::string> end;
          istream_iterator<std::string> it(strstr);

          while (!streamOfText.eof()){
                getline (streamOfText, readTextLine);
                cout<<readTextLine<<endl;

                stringstream strstr(readTextLine);
                // how should I initialize the iterators it and end here?

                }

編集:

コードをに変更しました

          vector<string> allTheText;
          stringstream strstr;
          istream_iterator<std::string> end;
          istream_iterator<std::string> it(strstr);

          while (getline(streamOfText, readTextLine)) {
               cout << readTextLine << endl;

        vector<string> vec((istream_iterator<string>(streamOfText)), istream_iterator<string>()); // generates RuntimeError


          }

そしてRuntimeErrorを取得しました、なぜですか?

4

1 に答える 1

9

while (!….eof())ストリームがエラー状態になったときにループが終了することはないため、C++でループを使用すると壊れます。

むしろ、ストリームの状態を直接テストする必要があります。コードに適応すると、これは次のようになります。

while (getline(streamOfText, readTextLine)) {
    cout << readTextLine << endl;
}

ただし、すでにストリームがあります。なぜそれを文字列ストリームにも入れるのですか?それとも、何らかの理由でこの行ごとに行う必要がありますか?

入力イテレータを使用してベクトルを直接初期化できます。copy適切なコンストラクターのオーバーロードがあるため、文字列ストリームを作成する必要はなく、アルゴリズムを使用する必要もありません。

vector<string> vec((istream_iterator<string>(cin)), istream_iterator<string>());

これを関数宣言から明確にするために必要な最初の引数の周りの余分な括弧に注意してください。

編集このコードが何をするかについての簡単な説明:

C ++は、範囲を指定する統一された方法を提供します。範囲は、入力された値の単なるコレクションであり、これらの値がどのように格納されるかについての詳細は説明しません。C ++では、これらの範囲は半開区間[ ab[。つまり、範囲は2つのイテレーターで区切られます(ポインターのようなものですが、より一般的です。ポインターは特別な種類のイテレーターです)。最初のイテレータ、aは、範囲の最初の要素を指します。2番目の、は、最後の要素の後ろbを指します。なぜ遅れているのですか?これにより、要素を非常に簡単に反復できるため、次のようになります。

for (Iterator i = a; i != b; ++i)
    cout << *i;

ポインターと同様に、イテレーターはそれらに適用することによって逆参照*されます。これはそれらの値を返します。

C ++のコンテナクラス(たとえばvectorlist)には、別の範囲から新しいコンテナに値を簡単にコピーできる特別なコンストラクタがあります。したがって、このコンストラクターは2つのイテレーターを想定しています。たとえば、次の例では、Cスタイルの配列をベクトルにコピーします。

int values[3] = { 1, 2, 3 };
vector<int> v(values, values + 3);

ここで、valuesはと同義で&values[0]あり、配列の最初の要素を指していることを意味します。values + 3、ポインタ演算のおかげで、ほぼ同等であり&values[3](ただし、これは無効なC ++です!)、配列の背後にある仮想要素を指します。

さて、上記の私のコードは、この最後の例とまったく同じです。唯一の違いは、使用するイテレータのタイプです。プレーンポインタを使用する代わりに、C++が提供する特別なイテレータクラスを使用します。このイテレータクラスは、入力ストリームを進め、ストリームから次の要素を読み取るような方法で入力ストリームをラップします。要素の種類は、type引数で指定されます(したがって、この場合)。++ *string

これを範囲として機能させるには、開始と終了を指定する必要があります。残念ながら、入力の終わりはわかりません(ユーザーがコンソールにさらに入力を入力すると、ストリームの終わりが実際に時間の経過とともに移動する可能性があるため、これは論理的です!)。したがって、仮想エンドイテレータを作成するために、のコンストラクタに引数を渡しませんistream_iterator。逆に、開始イテレータを作成するには、入力ストリームを渡します。次に、ストリーム内の現在の位置を指すイテレータを作成します(ここでは、cin)。

上記のコードは、機能的には次のコードと同等です。

istream_iterator<string> front(cin);
istream_iterator<string> back;

vector<string> vec;

for (istream_iterator<string> i = front; i != back; ++i)
    vec.push_back(*i);

これは、次のループを使用するのと同じです。

string word;
while (cin >> word)
    vec.push_back(word);
于 2009-01-27T21:05:52.093 に答える