How to read this kind of file?

P

PengYu.UT

Hi,

Suppose I a file with the following format --- each line is either a
record or a blank line.

If it is a record, it might be of one of the following format, where
the first format means t equals 1 by default.
w h
w h t

It is very simple to read this file if it only have "w h" record or "w
h t" record. Like the following tow code segments:

ifstream in_file;
int w, h
while(in_file >> w >> h){
....
}

ifstream in_file;
int w, h, t
while(in_file >> w >> h >> t){
....
}

But it is not very straight forward to me how to read a file with both
kinds of records. Would you please help me?

Best wishes,
Peng
 
R

Rapscallion

Suppose I a file with the following format --- each line is either a
record or a blank line.

If it is a record, it might be of one of the following format, where
the first format means t equals 1 by default.
w h
w h t

step 1: Read the whole line with getline() or fgtes(), respectively.
step 2: Parse the line (and you'll see if it contains 0, 2, or 3
tokens).
 
A

Alan Johnson

But it is not very straight forward to me how to read a file with both
kinds of records. Would you please help me?

Best wishes,
Peng

My preferred method is to roll everything up into a class or struct.
With your example, the result would look something like:

#include <iostream>
#include <string>
#include <sstream>

struct record
{
int w, h, t ;

// Put constructors and other members if you want them.
} ;

std::istream &operator>>(std::istream &is, record &r)
{
int w, h, t ;
std::string s ;

if (std::getline(is, s))
{
std::istringstream ss(s) ;
if (ss >> w >> h)
{
r.w = w ;
r.h = h ;

if (ss >> t)
r.t = t ;
else
r.t = 1 ;
}
}

return is ;
}

std::eek:stream &operator<<(std::eek:stream &os, const record &r)
{
os << r.w << ' ' << r.h << ' ' << r.t ;
}



Now you can do all sorts of neat stuff. You could read the file like
you were original trying to:

record r ;
while (in_file >> r) { ... }

But you could also easily create a whole vector/list/etc from your file
in one command:

#include <vector>
#include <algorithm>
#include <iterator>
....
std::vector<record> records ;
std::copy(std::istream_iterator<record>(in_file),
std::istream_iterator<record>(),
std::back_inserter(records)) ;


Or my favorite, you could create a function object to process a record,
and then process the whole file with one command:

class process_record
{
public :
void operator()(const record &r)
{
// Do some record processing.
std::cout << "I just processed record: "
<< r << std::endl ;
}
} ;

....

std::for_each(std::istream_iterator<record>(in_file),
std::istream_iterator<record>(),
process_record()) ;


Anyhow, I hope this at least gives you some ideas of how to approach
your problem. Good luck!

-Alan
 
A

Alan Johnson

I feel there are several getline functions. Is the following webpage
describe the one that you use?
http://www.cppreference.com/cppio/getline.html

I'm confused why the return value of "istream&" can be used as the
condition. Or do I read the wrong definition?

Best wishes,
Peng

Yes. That is the one used in my example.

The standard defines two functions named "getline". One is actually a
member function of the basic_istream template class. It let's you do
things along the lines of:

char buffer[1024] ;
cin.getline(buffer, 1024, '\n') ;

The other, used in the example code in previous posts, is defined as
part of the "Strings library" (clause 21 of the standard). It is
designed specifically to read from a stream into a std::string (or
std::wstring) object. The advantage of this form is that you don't have
to guess at how long a line is. It will keep reading into your string
object (which will keep resizing itself when appropriate) until you've
reached an end of line. The disadvantage, of course, is that you have
to use a string object, which may or may not be appropriate for your
task. For tasks that involve processing lines of text (like the one you
posed) this is usually the easiest approach (in my opinion).

-Alan
 
A

Alan Johnson

Alan said:
I feel there are several getline functions. Is the following webpage
describe the one that you use?
http://www.cppreference.com/cppio/getline.html

I'm confused why the return value of "istream&" can be used as the
condition. Or do I read the wrong definition?

Best wishes,
Peng

Yes. That is the one used in my example.

The standard defines two functions named "getline". One is actually a
member function of the basic_istream template class. It let's you do
things along the lines of:

char buffer[1024] ;
cin.getline(buffer, 1024, '\n') ;

The other, used in the example code in previous posts, is defined as
part of the "Strings library" (clause 21 of the standard). It is
designed specifically to read from a stream into a std::string (or
std::wstring) object. The advantage of this form is that you don't have
to guess at how long a line is. It will keep reading into your string
object (which will keep resizing itself when appropriate) until you've
reached an end of line. The disadvantage, of course, is that you have
to use a string object, which may or may not be appropriate for your
task. For tasks that involve processing lines of text (like the one you
posed) this is usually the easiest approach (in my opinion).

-Alan

Sorry, I answered incorrectly. The "getline" documented in the link you
included is the first form I mentioned above. The getline I used in the
example is the second form.

-Alan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top