Hello,

I have a text file to read in. It is of the format

! this is a comment
 ! this is another comment

8    3.3  2.2  5.6  6.7
4.4     5.5   4.4
1    3.3    2.3    34.5    5.5    10.3e10
1    3.3    2.3    34.5    5.5    10.3e10
1    3.3    2.3    34.5    5.5    10.3e10
1    3.3    2.3    34.5    5.5    10.3e10
1    3.3    2.3    34.5    5.5    10.3e10
1    3.3    2.3    34.5    5.5    10.3e10
1    3.3    2.3    34.5    5.5    10.3e10
1    3.3    2.3    34.5    5.5    10.3e10
...

ie there are some comment lines (preceded by a space then and exclaimation mark), followed by 8 numbers (int or float) split randomly between lines, then a matrix of values in 6 columns rows (and the first int gives the number of rows - ie 8 in this case)

I have added an example txt file as an attachment in case that helps

I would like to skip the comments and blank lines, read in the 8 header numbers, then read the matrix (better I would like to read each column of the matrix into an array).

I have had a play using fscanf, getline and then stringstream to split up the lines etc, but keep getting it wrong. Any guidance would be great. Here is the best shot I have so far following the fscanf route (the getline+stringstream option was getting cumbersome)...

double NUV;
double U0;
double V0;
double ZEROSP;
double BGS1;
double BGS2;
double INTCPT;
double SLOPE;

  string vis2_filename("example.tex");
  ifstream vis2_file(vis2_filename.c_str());
  if (vis2_file.is_open())
  {
        //skip the comments
	while (getline(inFile,product))
	{
	if (product[1] = '!')
	cout << product << '\n';
	}
    //read in the header
    fscanf(vis2_file, "%lf", &NUV);
    fscanf(vis2_file, "%lf", &U0);
    fscanf(vis2_file, "%lf", &V0);
    fscanf(vis2_file, "%lf", &ZEROSP);
    fscanf(vis2_file, "%lf", &BGS1);
    fscanf(vis2_file, "%lf", &BGS2);
    fscanf(vis2_file, "%lf", &INTCPT);
    fscanf(vis2_file, "%lf", &SLOPE);
    
//read in the matrix

	int Nvis2 = int(NUV);
	Row<double> vis2id(Nvis2);
	Row<double> ucoord(Nvis2);
	Row<double> vcoord(Nvis2);
	Row<double> r(Nvis2);
	Matrix<double> vis2_data(1,Nvis2);
	Matrix<double> vis2_err(1,Nvis2);
 
      for(int i = 0; i < Nvis2; i++)
      {
      fscanf(vis2_file, "%lf", &vis2id[i]);
      fscanf(vis2_file, "%lf", &ucoord[i]);
      fscanf(vis2_file, "%lf", &vcoord[i]);
      fscanf(vis2_file, "%lf", &r[i]);
      fscanf(vis2_file, "%lf", &vis2_data[0][i]);
      fscanf(vis2_file, "%lf", &vis2_err[0][i]);
      }  

    vis2_file.close();
    }

Thanks in advance - I am sure this is strait forward, but file input has always been my weakness in c++ and I am going round in circles on google.


Regards

Jimbo

1-There is no (inFile,product)??
2-while (getline -->will skip the whole file not the comment

//skip the comments
	while (getline(inFile,product))
	{
	   if (product[1] = '!')
   	   cout << product << '\n';
	}

thanks for the quick reply

1-There is no (inFile,product)??

you are quite correct, my quickly thrown together example from several attempts was supposed to be

while (getline(vis2_file,product))

and I had removed the

string product;

line whilst trimming the fat from my example. sorry

2-while (getline -->will skip the whole file not the comment

//skip the comments
	while (getline(inFile,product))
	{
	   if (product[1] = '!')
   	   cout << product << '\n';
	}

ahh. not intended. I was hoping I could loop over lines that contained comments then start reading the useful stuff using fscanf. Any suggestion how to read a line, and if comment or blank move on, then when it reaches something that is not a comment it changes to reading individual values in using fscanf?

Thanks again for the quick reply

Jimbo

just

if (product[0] = '!')
{
   cout << product << '\n';
   break;
}

just

if (product[0] = '!')
{
   cout << product << '\n';
   break;
}

Hi, so I tried a variation of this...

while (getline(vis2_file,product))
	{
	   if (product[1] == '!')
           {
           cout << product << '\n';
           } 
	   else
	   {
	   break;
	   }     
	}

which prints out the comments nicely, and seems to break in the right place - ie it does not print any of the non-commented lines. The problem is that the following fscan lines do not seem to pass the text values to the arrays - when I cout any of the values I get the crazy small numbers associated with undesignated variables.

As I understand it, the fscanf command should scan through the file (starting where my break statement is??) ignoring whitespace and linebreaks to read in any characters (in the format specified.) This sounds exactly right for my application, but there must be a subtelty that I am missing.

Thanks again for the help

Jimbo

I should add, I had to remove the

if (vis2_file.is_open())

as the break command exits this as well (I think)

fscanf doesnot work with ifstream it needs FILE so try to use getline and split on space

or try read to space
getline (vis2_file,product," ")

Right, thanks to your direction, I have a working example...

double NUV;
double U0;
double V0;
double ZEROSP;
double BGS1;
double BGS2;
double INTCPT;
double SLOPE;

//VIS2 - Works for .calvis data
  string holder;
  string comment;
  string sNUV, sU0, sV0, sZEROSP, sBGS1, sBGS2, sINTCPT, sSLOPE;
  string svis2id, sucoord, svcoord, sr, svis2_data, svis2_err;
  ifstream vis2_file("/home/jimbo/UKIRT/cah_reduction_ukirt97/N2/10216K/10216.calvis");

    while (getline(vis2_file,comment))
    {
      if (comment[1] == '!')
      {
         cout << comment << '\n';
      } 
      else
      { 
        sNUV = comment;
        break;
      }     
    }

    //read in header data
    vis2_file  >> sU0 >> sV0 >> sZEROSP >> sBGS1 >> sBGS2 >> sINTCPT >> sSLOPE;
    //convert to numbers
    NUV = atof ( sNUV.c_str() );
    U0 = atof ( sU0.c_str() );
    V0 = atof ( sV0.c_str() );
    ZEROSP = atof ( sZEROSP.c_str() );
    BGS1 = atof ( sBGS1.c_str() );
    BGS2 = atof ( sBGS2.c_str() );
    INTCPT = atof ( sINTCPT.c_str() );
    SLOPE = atof ( sSLOPE.c_str() );

    int Nvis2 = int(NUV);
    Row<double> vis2id(Nvis2);
    Row<double> ucoord(Nvis2);
    Row<double> vcoord(Nvis2);
    Row<double> r(Nvis2);
    Row<double> vis2_data(Nvis2);
    Row<double> vis2_err(Nvis2);
 
    for(int i = 0; i < Nvis2; i++)
    {
      //read in data
      vis2_file >> svis2id >> sucoord >> svcoord >> sr >> svis2_data >> svis2_err;
      //convert to numbers
      vis2id[i] = atof ( svis2id.c_str() );
      ucoord[i] = atof ( sucoord.c_str() );
      vcoord[i] = atof ( svcoord.c_str() );
      r[i] = atof ( sr.c_str() );
      vis2_data[i] = atof ( svis2_data.c_str() );
      vis2_err[i] = atof ( svis2_err.c_str() );
    }  

    vis2_file.close();

The only problem (apart from being ugly) is that it assumes that the first line of header data only contains one number (which is true in the case of this particular file but may not be in future).

The problem is that I loose a line when the comments checker performs a getline and it is decided that the line is not a comment.

I guess there is a way to count the number of comment lines, and then restart the file input skipping that number of lines. That way I could start the >> in the right plase and read in the first variable I need

Thanks

Jimbo

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.