18

次のようなデータファイルを読み込む必要があります。

* SZA: 10.00
 2.648  2.648  2.648  2.648  2.648  2.648  2.648  2.649  2.650  2.650
 2.652  2.653  2.652  2.653  2.654  2.654  2.654  2.654  2.654  2.654
 2.654  2.654  2.654  2.655  2.656  2.656  2.657  2.657  2.657  2.656
 2.656  2.655  2.655  2.653  2.653  2.653  2.654  2.658  2.669  2.669
 2.667  2.666  2.666  2.664  2.663  2.663  2.663  2.662  2.663  2.663
 2.663  2.663  2.663  2.663  2.662  2.660  2.656  2.657  2.657  2.657
 2.654  2.653  2.652  2.651  2.648  2.647  2.646  2.642  2.641  2.637
 2.636  2.636  2.634  2.635  2.635  2.635  2.635  2.634  2.633  2.633
 2.633  2.634  2.634  2.635  2.637  2.638  2.637  2.639  2.640  2.640
 2.639  2.640  2.640  2.639  2.639  2.638  2.640  2.640  2.638  2.639
 2.638  2.638  2.638  2.638  2.637  2.637  2.637  2.634  2.635  2.636
 2.637  2.639  2.641  2.641  2.643  2.643  2.643  2.642  2.643  2.642
 2.641  2.642  2.642  2.643  2.645  2.645  2.645  2.645

このファイルをfloatの配列に読み込む最も洗練された方法は何でしょうか。

私は、各1行を文字列に読み取る方法と、を使用して文字列をfloatに変換する方法を知っていますatof()。しかし、どうすれば残りを最も簡単に行うことができますか?

文字列バッファについて聞いたことがありますが、これは役に立ちますか?

4

4 に答える 4

18

String Toolkit Library(Strtk)には、問題に対する次の解決策があります。

#include <iostream>
#include <string>
#include <deque>
#include <iterator>

#include "strtk.hpp"

int main()
{
    std::deque<float> flist;
    strtk::for_each_line("file.txt",
                         [&flist](const std::string& line)
                         { strtk::parse(line," ",flist); }
                         );
    std::copy(flist.begin(),flist.end(),
              std::ostream_iterator<float>(std::cout,"\t"));
    return 0;
}

その他の例は、C ++ String Toolkit(StrTk)Tokenizerにあります。

于 2009-08-24T21:42:40.153 に答える
11

これはC++としてタグ付けされているため、最も明白な方法はストリームを使用することです。私の頭のてっぺんから、このようなことが起こるかもしれません:

std::vector<float> readFile(std::istream& is)
{
  char chdummy;
  is >> std::ws >> chdummy >> std::ws; 
  if(!is || chdummy != '*') error();
  std::string strdummy;
  std::getline(is,strdummy,':');
  if(!is || strdummy != "SZA") error();

  std::vector<float> result;
  for(;;)
  {
    float number;
    if( !is>>number ) break;
    result.push_back(number);
  }
  if( !is.eof() ) error();

  return result;
}

なぜfloat、ところで?通常、doubleはるかに優れています。

編集、のコピーを返すことがvector良い考えであるかどうかが疑問視されたので:

最初の解決策として、私は確かに明白なことをします。関数ファイルをに読み込んでいます。関数が実行vectorする最も明白なことは、その結果を返すことです。これが顕著な速度低下をもたらすかどうかは、多くの事柄に依存します(ベクトルのサイズ、関数が呼び出される頻度と場所、これが読み取るディスクの速度、コンパイラーがRVOを適用できるかどうか)。最適化で明白なソリューションを台無しにしたくはありませんが、プロファイリングでこれが遅いことが実際に示されている場合は、非定数参照ごとにベクトルを渡す必要があります。

(また、右辺値をサポートするC ++ 1xは、関数から戻ったときにベクトルがコピーされないようにするため、この議論は議論の余地があります。)

于 2009-08-24T18:08:49.413 に答える
2

私はこのようなことをします:

std::ifstream input("input.txt");
std::vector<float> floats;
std::string header;
std::getline(input, header); // read in the "* SZA: 10.00" line
if(header_is_correct(header)) {
    float value;
    // while we could successfully read in a float from the file...
    while(input >> value) {
        // store it in the vector.
        floats.push_back(value);
    }
}

注: header_is_correct(header)これは単なる例であり、最初の行のエラーチェックを手動で実装する必要があります。

于 2009-08-24T19:49:18.523 に答える
2

STLアルゴリズムを使用した簡単なソリューション:

#include <vector>
#include <iostream>
#include <string>
#include <iterator>

struct data
{
   float first; // in case it is required, and assuming it is 
                // different from the rest
   std::vector<float> values;
};

data read_file( std::istream& in )
{
   std::string tmp;
   data d;
   in >> tmp >> tmp >> d.first;
   if ( !in ) throw std::runtime_error( "Failed to parse line" );

   std::copy( std::istream_iterator<float>( in ), std::istream_iterator<float>(),
         std::back_inserter<float>(d.values) );

   return data;
}

本当に配列を使用する必要がある場合は、最初に配列を割り当てる必要があり(サイズがわかっている場合は動的または静的に)、次に同じコピーアルゴリズムを使用できます。

// parsing the first line would be equivalent
float data[128]; // assuming 128 elements known at compile time
std::copy( std::istream_iterator<float>(is), std::istream_iterator<float>(), 
      data );

ただし、この場合でもstd :: vectorを使用することをお勧めします。配列を受け取る関数にデータを渡す必要がある場合は、いつでも最初の要素へのポインターとして渡すことができます。

void f( float* data, int size );
int main()
{
   std::vector<float> v; // and populate
   f( &v[0], v.size() ); // memory is guaranteed to be contiguous
}
于 2009-08-24T22:40:38.600 に答える