2

このような.datファイルから多くのデータポイントを取得しました

 + (  0.00000000E+00   0.00000000E+00     //this '(' happens once per block of data
 +    0.99999997E-04   0.00000000E+00
 +    0.19999999E-03   0.00000000E+00
 +    ...

このデータを吐き出すプログラムを、より使いやすくすることはできません。

これまでのところ、各行をベクトルで取得し、それらを解析したいので、処理する数値しかありませんが、.dat ファイルを使用する別のプログラムのために、.dat ファイルの整合性を維持したいと考えています。は。

各文字列をスペースで区切ることを考えていましたが、スペースはサイズが異なり(問題がない場合を除く)、それらをベクトルに配置して必要なデータのみを取得しますが、データの最初の行には4つの文字列があり、残りの行は 3 です。

どんな助けでも大歓迎です

編集: 元の .dat ファイルを取得してトレースし、しきい値を満たさないデータのブロックはすべて無視されます。そうするものはすべて、新しいファイルに書き込まれます。この新しいファイルのすべては、元のファイルとまったく同じでなければなりません。もちろん、必要のないデータは除きます。

[JD] コメントごとに編集:

これらの行を解析し、その行について何も削除せずにすべてを同じに保ち、数値を取得して、保持する必要があるものと必要でないものを処理するにはどうすればよいでしょうか?

4

3 に答える 3

3

+および([編集: and ), based on comment] を空白として分類する ctype ファセットを作成し、数字を読み取るだけです。数値を維持するための基準が、たとえば 1.0e-4 より大きいことであると仮定しましょう。データを新しいファイルにコピーして小さい数字を削除するには、次のようにします。

#include <locale>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <sstream>
#include <numeric>

class my_ctype : public
std::ctype<char>
{
    mask my_table[table_size];
public:
    my_ctype(size_t refs = 0)  
        : std::ctype<char>(&my_table[0], false, refs)
    {
        std::copy_n(classic_table(), table_size, my_table);
        my_table['('] = (mask)space;
        my_table['+'] = (mask)space;
        my_table[')'] = (mask)space;
    }
};

int main() {
    std::locale x(std::locale::classic(), new my_ctype);
    std::cin.imbue(x);

    std::remove_copy_if(std::istream_iterator<double>(std::cin), 
        std::istream_iterator<double>(), 
        std::ostream_iterator<double>(std::cout, "\n"), 
        [](double in){return in < 1.0e-4; }); // criterion for removing a number
    return 0;
}

数値を削除するための基準は、おそらく単純な比較よりも少し複雑だと思います (ただし、実際にはわかりません)。より複雑になる場合は、ラムダの代わりに手動で定義したファンクターを使用して基準を定義することをお勧めします。ただし、コードの残りの部分 (特にデータを読み取る部分) はおそらく変更されないままです。

また、そのままの状態で、出力に 1 行に 1 つずつ数値を書き込んだことにも注意してください。元の形式に近いものを維持する必要があるかどうかはわかりません。

于 2012-06-22T15:11:22.433 に答える
0

operator>>空白をスキップするファイル ストリームの を使用して、一度に各項目を取得できます。「(」または空白 (空白など) になる列に到達したら、それを確認し、取得した内容に基づいて切り替えます。「(」operator>>を取得した場合は、もう一度実行して実際のデータを取得します。そうしなかった場合は「」 '(' を取得すると、operator>>空白がスキップされるため、データが得られます。

うまくいけば完全な例です:

#include <string>
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
using namespace std;

struct Inbound
{
    std::string  a_, b_;
};

int main()
{
    ifstream f("c:\\dev\\hacks\\data.txt");

    while( !f.bad() && !f.eof() )
    {
        string s;
        f >> s; // should be '+' -- discard
        f >> s; // either '(' or first datum
        if( s == "(" )
            f >> s; // get the first datum
        Inbound in;
        in.a_ = s;
        f >> in.b_;

        cout << "Got: " << in.a_ << "\t" << in.b_ << endl;
    }

}

出力:

Got: 0.00000000E+00     0.00000000E+00
Got: 0.99999997E-04     0.00000000E+00
Got: 0.19999999E-03     0.00000000E+00
于 2012-06-22T15:16:20.447 に答える
0

各データを取得するには、文字列トークナイザーを使用する必要があります。すでに使用しているライブラリによっては、非常に簡単な場合があります。

それ以外の場合は、 strtokを使用して非常に単純にすることができます 。

MS CString を使用している場合は、次のように自分でコーディングできます。

CStringArray TokenizeString(const CString& str, const CString &sep)
{
    CStringArray elements;

    CString item = "";
    CString strCpy = str;
    long sepPos = strCpy.Find(sep);

    while (sepPos != -1)
    {
        // extract item
        item = strCpy.Left(sepPos);
            // add it to the list
        elements.Add(item);
        // prepare next loop
        strCpy = strCpy.Right(strCpy.GetLength() - sepPos - sep.GetLength()); // get the right part of the string (after the found separator)
        sepPos = strCpy.Find(sep);
    }

    // add last item if needed (remaining part of the string)
    if (!strCpy.IsEmpty()) elements.Add(strCpy);
}

お役に立てれば !

于 2012-06-22T14:42:43.167 に答える