Originally Posted by
laserlight
Formatted input with operator>> skips whitespace only. You could use getline() with '=', or use getline() to read the entire line into a string and then break it on the '='.
Yeah that's what I ended up doing actually. I used getline(). Funny thing though about the logic behind the stream state. My basic routine looks like this:
Code:
typedef std::map<std::string, double> parmap ;
typedef enum {VARKEY, NUMVAL, NEWLINE} parstate ;
parmap parsefile(const std::string filename)
{
using namespace std ;
parmap pmap ;
int linenum = 1 ;
ifstream fstr(filename.c_str(), ifstream::in) ;
rassert(fstr.is_open(), " Can't open " + filename) ;
string vname , dstr ;
double dval ;
// initial parser state
parstate pstate = VARKEY ;
while(fstr.good()) {
switch (pstate) {
case VARKEY:
getline(fstr, vname, '=') ;
//rassert(fstr.good(), "line: " + to_string(linenum) + " expecting = ") ;
if (fstr.good()) {
/* validate variable name */
rassert(isalpha(vname.at(0)),"line: " + to_string(linenum) +
" " + vname + " Is not a valid variable name") ;
pstate = NUMVAL ;
}
break ;
case NUMVAL:
fstr >> dval ;
/* insert into map */
pmap[vname] = dval ;
pstate = NEWLINE ;
break ;
case NEWLINE:
/* discard the newline */
getline(fstr, vname) ;
linenum++ ;
pstate = VARKEY ;
break ;
default:
rassert(false, " unknown parser state") ;
}
} // end while(fstr)
fstr.close() ;
return(pmap) ;
} // end parsefile()
rassert() is just an assert like routine that throws an exception with a dumb message.
to_string() just converts the numerical object to a string. I realize I didn't have to set this up as a state machine since the states occur sequentially, however just in case I wanted to extend the parser I thought it was a good idea to use this type of format.
Now I had originally thought I'd do a little bit of validation of the input text formatting. In particular if I were expecting a variable name, it should be followed by an '=' character, hence the getline(fstr, vname, '=') ; statement.
My problems began when I realized that my input files have each assignment statement delimitted by a newline, so I decided to make that a requirement, hence the extra getline() in the NEWLINE state. Without this, in fact the getline() in the next VARKEY state would return with an empty variable and I would throw an exception (I think) when I tried to read a double.
But the trouble occurs at the end of the file. Suppose there is no newline; well the last getline terminates (I thought) at eof. I thought this would set the state of the stream so that it would then kick out of the loop and all would be well. Nope. It requires another getline call to get an error state in the stream. The simple way for me to handle this was to disable the error checking in the VARKEY state and let the loop kick back up to the while conditional after calling getline() one last (IMHO unnecessary) time.
That's how I ended up with this ugly (but working) code.