1

整数と特殊文字「#」を含む入力ストリームがあります。... 12 18 16 # 22 24 26 15 # 17 # 32 35 33 ... トークンはスペースで区切られています。 「#」の位置にパターンはありません。

次のように入力ストリームをトークン化しようとしていました。

int value;
std::ifstream input("data");
if (input.good()) {
  string line;
  while(getline(data, line) != EOF) {
    if (!line.empty()) {
      sstream ss(line);
      while (ss >> value) {
        //process value ...

      }
    }
  }
}

このコードの問題は、最初の「#」に遭遇したときに処理が停止することです。

私が考えることができる唯一の解決策は、個々のトークンを文字列 (「#」ではなく) に抽出し、atoi() 関数を使用して文字列を整数に変換することです。ただし、過半数のトークンが整数であるため、非常に非効率的です。トークンで atoi() を呼び出すと、大きなオーバーヘッドが発生します。

個々のトークンをそのタイプで解析する方法はありますか? つまり、整数の場合は整数として解析し、'#' の場合はスキップします。ありがとう!

4

6 に答える 6

2

可能性の 1 つは、空白 ( ss >> std::ws) を明示的にスキップし、 を使用して a が続くss.peek()かどうかを調べることです。#はいの場合は、 を使用ss.get()して読み取り、続行します。そうでない場合は、 を使用ss >> valueして値を読み取ります。

の位置が#重要でない場合は'#'、行を初期化する前に行からすべてを削除することもできますstringstream

于 2012-10-06T19:06:51.483 に答える
2

通常、good() に対してテストする価値はありません

if (input.good()) {

次の操作でエラー メッセージまたは例外が生成されない限り。それが良くない場合、それ以降のすべての操作はいずれにせよ失敗します。

に対してテストしないでくださいEOF

while(getline(data, line) != EOF) {

std::getline() の結果は整数ではありません。入力ストリームへの参照です。入力ストリームは、bool コンテキスト (など) で使用できる bool のようなオブジェクトに変換できますwhile if。だからあなたがしたいこと:

while(getline(data, line)) {

一行読めるかどうかわからない。単語を読むだけで済みます (入力はスペースで区切られているため)。文字列で >> 演算子を使用する

std::string word;
while(data >> word) {  // reads one space separated word

これで、単語をテストして、それが特殊文字かどうかを確認できます。

if (word[0] == "#")

そうでない場合は、単語を数値に変換します。

これは私がすることです:

// define a class that will read either value from a stream
class MyValue
{
  public:
    bool isSpec() const {return isSpecial;}
    int  value()  const {return intValue;}

    friend std::istream& operator>>(std::istream& stream, MyValue& data)
    {
        std::string item;
        stream >> item;
        if (item[0] == '#') {
            data.isSpecial = true;
        } else
        {   data.isSpecial = false;
            data.intValue  = atoi(&item[0]);
        }
        return stream;
    }
  private:
    bool isSpecial;
    int  intValue;
};

// Now your loop becomes:
MyValue  val;
while(file >> val)
{
    if (val.isSpec())  { /* Special processing */ }
    else               { /* We have an integer */ }
}
于 2012-10-06T21:07:32.013 に答える
1

おそらく、すべての値を std::string として読み取り、それが「#」であるかどうかを確認できます (そうでない場合は、int に変換します)。

于 2012-10-06T19:09:27.490 に答える
1
int value;
std::ifstream input("data");
if (input.good()) {
    string line;
    std::sstream ss(std::stringstream::in | std::stringstream::out);
    std::sstream ss2(std::stringstream::in | std::stringstream::out);
    while(getline(data, line, '#') {
        ss << line;
        while(getline(ss, line, ' ') {
            ss2 << line;
            ss2 >> value
            //process values ...
            ss2.str("");  
        }
        ss.str("");
    }
}

ここでは、まず最初の while ループで行をトークン '#' で分割し、次に 2 番目の while ループで ' ' で行を分割します。

于 2012-10-06T19:50:08.197 に答える
0

個人的には、セパレーターが常にスペースである場合は、入力を文字列として取得し、そこから解析することをお勧めします。そうすれば、文字列を取得して、それが数字なのか # なのかなどを確認できます。

于 2012-10-06T19:08:46.977 に答える
0

「トークンでatoi()を呼び出すと大きなオーバーヘッドが発生する」という前提を再検討する必要があると思います-

に魔法はありませんstd::cin >> val。内部的には、最終的に atoi (に非常によく似たもの) を呼び出します。

トークンが巨大な場合、a を作成するためのオーバーヘッドが発生する可能性がありますstd::stringが、あなたが言うように、大部分は数字 (残りは #) であるため、ほとんどは短くする必要があります。

于 2012-10-06T19:10:19.600 に答える