I have a text file arranged as:
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
I need to do two things, first I need to read the number of points, so basically read how many lines start with Point, for this I wrote:
#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;
}
This gives me the correct number of points (although improvements in the code are welcome), and secondly I need to read the x, y, and z coordinates and disregard everything else. Not sure how to go about this, any suggestions?
Thanks in advance!
EDIT:
Thanks everybody for great ideas and answers! Captain Obvlious provided a great answer, and I want so see if it can be adapted a bit.
So, turns out the .txt file will have the format:
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
Again, I only need the first column of values, everything else after that can be discarded.
I used int
for simplicity but the numbers will be double
.
After the reading I am trying to place the values in an armadillo matrix, so my matrix looks like:
cout << matrix << endl;
2 5 6
4 2 0
4 1 2
So, I modified Captain Obvlious' solution to place the data in the matrix:
#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;
}
Not sure where to place the loop over k that sets the row of the matrix to allocate the values. Sorry for the super long post, and thank you in advance for any help. This is pretty useful stuff to have around for future reference in my opinion.