2

我有一个文本文件安排为:

Diam
<D>          4.2      
05:21:26 02:Apr:2012
Point 1
<X>       2   
<Y>       5
<Z>       6  
Point 2
<X>       4   
<Y>       2
<Z>       0
Point 3
<X>       4 
<Y>       1 
<Z>       2 
End
End

我需要做两件事,首先我需要读取点数,所以基本上读取了以 Point 开头的行数,为此我写了:

#include <iostream>
#include <string>

using namespace std;

int main()
{
    //count number of data points in file (only count lines starting with P)
    const char FileName[] = "myfile.txt";
    int num = 0.;
    string line;
    ifstream file;
    file.open (FileName);
    while(file.eof() == false)
    {
        getline(file, line);
        if (line[0]=='P')  num++;
    }
    file.close();

    return 0;
}

这给了我正确的点数(尽管欢迎对代码进行改进),其次我需要阅读 x、y 和 z 坐标并忽略其他所有内容。不知道该怎么做,有什么建议吗?

提前致谢!

编辑:

感谢大家的好主意和答案!Obvlious 船长提供了一个很好的答案,我想看看它是否可以调整一下。

因此,事实证明 .txt 文件将具有以下格式:

Diam
<D>          4.2      5    6    4   2
05:21:26 02:Apr:2012
Point 1
<X>       2   5    6    4   2
<Y>       5   4    4    8   3
<Z>       6   7    6    0   2
Point 2
<X>       4   2    6    4   2
<Y>       2   3    5    8   4
<Z>       0   7    6    3   2
Point 3
<X>       4   0    6    2   2
<Y>       1   5    6    7   4
<Z>       2   0    6    5   3
End
End

同样,我只需要第一列值,之后的所有其他内容都可以丢弃。我int为简单起见,但数字将是double. 阅读后,我试图将值放在犰狳矩阵中,所以我的矩阵看起来像:

cout << matrix << endl;
2 5 6
4 2 0
4 1 2 

因此,我修改了 Captain Obvlious 的解决方案,将数据放入矩阵中:

#include <iostream>
#include <fstream>
#include <string>
#include <cctype>
#include <sstream>
#include <stdexcept>
#include <armadillo>

using namespace std;
using namespace arma;

int main()
{
    mat matrix(3,3);  //here is where I set the size of the matrix, 
                      //different files have different number of points,
                      //that's why I use my counting points code to set the size.
    const char FileName[] = "myfile.txt";
    string line;
    ifstream file;
    file.open (FileName);

    for(;;)
    {
        getline(file, line);
        if( file.eof() ) {
            break;
        }

        if (line.size() && line[0]=='P')
        {
            // Change "int" to "double" if necessary.
            struct { double  x, y, z; } data;

            for(int i = 0; i < 3; i++)
            {
                getline(file, line);
                if(line.size() > 3 && line[0] == '<' && line[2] == '>')
                {
                    string::value_type pointElement = line[1];

                    // skip spaces and process data here to get the value
                    string::size_type offset = line.find(' ');
                    if(string::npos == offset)
                    {
                        throw invalid_argument("Invalid data format");
                    }

                    stringstream sline(line.substr(offset));
                    int value;
                    if(!(sline >> value))
                    {
                        throw invalid_argument("invalid data format");
                    }


                    switch(pointElement)
                    {
                    case 'X':   data.x = value; break;
                    case 'Y':   data.y = value; break;
                    case 'Z':   data.z = value; break;
                    default:
                        // error in data format
                        throw invalid_argument("invalid data format");
                    }
                }
                else
                {
                    // error in data format
                    throw invalid_argument("invalid data format");
                }
            }

            // Do something with the values in data
            cout
                << "point[x=" << data.x
                << ", y=" << data.y
                << ", z=" << data.z
                << "]" << endl;
            // place data in matrix
            // need to loop over k where k is the row of the matrix
            matrix(k,0) = data.x; // format is matrix(rows,columns)
            matrix(k,1) = data.y;
            matrix(k,2) = data.z;
        }
    }
    file.close();

    return 0;
}

不确定将循环放置在 k 上的位置,该循环设置矩阵的行以分配值。很抱歉这篇超长的帖子,并提前感谢您的帮助。在我看来,这是非常有用的东西,可供将来参考。

4

6 回答 6

2

您需要单独处理每个点的数据线并将它们存储到某种类型的数据结构中,以便在加载 X、Y 和 Z 之后对其进行处理。您还应该包含一些额外的验证代码,否则您可能会引入未定义的行为。有几种方法可以做到这一点,有些方法会导致您重复代码,有些方法会在处理完数据后专注于分配数据。

下面的解决方案考虑了验证和必须从 3 个单独的行读取数据的事实。它并不完美,并且希望“myfile.txt”文件具有精确的格式。它使用异常来处理数据格式中的错误,并添加一个数据结构来在加载数据时保存数据。

#include <iostream>
#include <fstream>
#include <string>
#include <cctype>
#include <sstream>
#include <stdexcept>

using namespace std;

int main()
{
    const char FileName[] = "myfile.txt";
    string line;
    ifstream file;
    file.open (FileName);

    for(;;)
    {
        getline(file, line);
        if( file.eof() ) {
            break;
        } 

        if (line.size() && line[0]=='P')
        {
            // Change "int" to "double" if necessary.
            struct { int x, y, z; } data;

            for(int i = 0; i < 3; i++)
            {
                getline(file, line);
                if(line.size() > 3 && line[0] == '<' && line[2] == '>')
                {
                    string::value_type pointElement = line[1];

                    // skip spaces and process data here to get the value
                    string::size_type offset = line.find(' ');
                    if(string::npos == offset)
                    {
                        throw invalid_argument("Invalid data format");
                    }

                    stringstream sline(line.substr(offset));
                    int value;
                    if(!(sline >> value))
                    {
                        throw invalid_argument("invalid data format");
                    }


                    switch(pointElement)
                    {
                    case 'X':   data.x = value; break;
                    case 'Y':   data.y = value; break;
                    case 'Z':   data.z = value; break;
                    default:
                        // error in data format
                        throw invalid_argument("invalid data format");
                    }
                }
                else
                {
                    // error in data format
                    throw invalid_argument("invalid data format");
                }
            }

            // Do something with the values in data
            cout
                << "point[x=" << data.x
                << ", y=" << data.y
                << ", z=" << data.z
                << "]" << endl;
        }
    }
    file.close();

    return 0;
}

当针对“myfile.txt”运行时,它会产生以下输出

点[x=2, y=5, z=6]
点[x=4, y=2, z=0]
点[x=4, y=1, z=2]

于 2013-05-28T20:08:46.823 回答
1

在你的while循环中,你总是可以添加这样的东西:

if(line.size() > 3){
  if(line[0] == '<' && line[1] == 'X' && line[2] == '>'){
    //enter code here
  } else if(line[0] == '<' && line[1] == 'Y' && line[2] == '>'){
    //enter code here
  } else if(line[0] == '<' && line[1] == 'Z' && line[2] == '>'){
    //enter code here
  }
}

然后执行类似子字符串的操作并删除 < X > / < Y > / < Z > 和任何空格或特殊字符。

之后,您可以将剩余的字符串转换为您需要的任何内容

编辑:稍微好一点的方法

  if(line.find("< X> ") != string::npos){
     //enter code here
  } else if(line.find("< Y> ") != string::npos){
     //enter code here
  } else if(line.find("< Z> ") != string::npos){
     //enter code here
  } 
于 2013-05-28T19:39:26.557 回答
1

也许您想考虑使用 ifstream/stringstreams 让您的生活更轻松,尽管这不是最快的方法......

int pt[3];
string line,dummy;

... //to where you were
  if (line[0]=='P')
    {
        num++;
        for (int i =0; i<3; ++i)
        {
            getline(file,line);
            stringstream ss(line);
            ss>>dummy;
            ss>>pt[i];
            std::cout<<"got "<<pt[i]<<std::endl;
        }
    }

您还应该包括 sstream 和 fstream

于 2013-05-28T19:53:53.483 回答
0

这与 S Grimminck 的答案非常相似。

#include <iostream>
#include <string>
using namespace std;
int main()
{
const char FileName[] = "myfile.txt";

int num = 0;
int x = 0;
int y = 0;
int z = 0;
string line;
std::stringstream str_parse(line);
ifstream file;
file.open (FileName);

while(file.eof() == false)
{
    getline(file, line);

    if (line[0]=='P')  
        num++;
    if( line.size() > 3 )
    {
    if( (line[0] == '<') && (line[1] == 'X') && (line[2] == '>'))
    {
       line = line.substr(3,line.size());
       str_parse>>x; // Gets the x-coordinate
    } 
    else if((line[0] == '<') && (line[1] == 'Y') && (line[2] == '>'))
    {
       line = line.substr(3,line.size());
       str_parse>>y;  // Gets the y-coordinate
    } 
    else if((line[0] == '<') && (line[1] == 'Z') && (line[2] == '>'))
    {
       line = line.substr(3,line.size());
       str_parse>>z;  // Gets the z-coordinate
    }
    }
}
file.close();

return 0;
}    

这是我第一次使用stringstream. 所以,我可能是错的。随时纠正我。:)

于 2013-05-28T19:49:51.247 回答
0

真的需要提前算点数吗?为什么不只对输入文件进行一次传递?

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

using namespace std;

struct Point {
    Point() {}
    Point(int x_, int y_, int z_) : x(x_), y(y_), z(z_) {}

    int x, y, z;
};

istream& operator>>(istream& is, Point& p) {
    is >> ws;

    if (is.peek() != 'P') {
        is.setstate(ios::failbit);
        return is;
    }

    string pointStr;
    is >> pointStr;
    if (pointStr != "Point") {
        is.setstate(ios::failbit);
        return is;
    }

    int pointIdx;
    is >> pointIdx;

    string coordStr;
    int x, y, z;

    is >> coordStr;
    if (coordStr != "<X>") {
        is.setstate(ios::failbit);
        return is;
    }
    is >> x;

    is >> coordStr;
    if (coordStr != "<Y>") {
        is.setstate(ios::failbit);
        return is;
    }
    is >> y;

    is >> coordStr;
    if (coordStr != "<Z>") {
        is.setstate(ios::failbit);
        return is;
    }
    is >> z;

    p = Point(x, y, z);

    return is;
}

int main() {
    ifstream fileStream("data.txt");

    string diamStr;
    fileStream >> diamStr;
    if (diamStr != "Diam")
        throw istream::failure("Badly formatted file");

    string dStr;
    fileStream >> dStr;
    if (dStr != "<D>")
        throw istream::failure("Badly formatted file");
    double diam;
    fileStream >> diam;

    string time, date;
    fileStream >> time >> date;

    istream_iterator<Point> pointIt(fileStream);
    vector<Point> points;
    copy(pointIt, istream_iterator<Point>(), back_inserter(points));

    cout << points.size() << " points:\n";
    for_each(begin(points), end(points), [](const Point& p) {
        cout << "(" << p.x << ", " << p.y << ", " << p.z << ")\n";
    });
}
于 2013-05-28T20:36:20.710 回答
0

您可以像这样创建一个坐标数组:int coords[num*3];

然后,使用模函数将坐标数存储在它们各自的位置,并找到位置,对于 x 坐标,pos mod 3 = 0,对于 y 坐标,pos mod 3 = 1,对于 z 坐标,pos mod 3 = 2。

于 2013-05-28T21:15:26.500 回答