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

我会创建一个 ctype facet,将[Edit: and +, based on comment] 分类为空白,然后只读取数字。假设您保留一个数字的标准是它大于 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;
}

我猜想(但不知道)你删除数字的标准可能比简单的比较复杂一点。如果它变得更复杂,您可能希望使用手动定义的仿函数而不是 lambda 来定义您的标准。其余代码(尤其是读取数据的部分)可能保持不变。

另请注意,我只是将数字写入输出,每行一个。我不知道您是否需要保持更接近原始格式的内容,所以目前我只是保持简单。

于 2012-06-22T15:11:22.433 回答
0

您可以使用文件流一次获取每个项目operator>>,这将跳过空格。当您到达将是“(”或空白(例如,空格)的列时,检查它并根据您获得的内容进行切换。如果您有“(”,请operator>>再次获取实际数据。如果您没有t 得到 '(',然后你得到了数据,因为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 回答