Read lines from .txt file?

M

mlt

I have a file containing:

w = 23
h = 34
S = 2

I would like to read this text file into variables in a program like:
std::string file = "args.txt";
std::ifstream infile;
infile.open (&file[0]);

int w,h,S;

w = infile.??
h = infile.??
S = infile.??


But how do I read the value on each line in the file after the '=' to a
variable in my program?
 
I

Ian Collins

mlt said:
I have a file containing:

w = 23
h = 34
S = 2

I would like to read this text file into variables in a program like:
std::string file = "args.txt";
std::ifstream infile;
infile.open (&file[0]);

int w,h,S;

w = infile.??
h = infile.??
S = infile.??


But how do I read the value on each line in the file after the '=' to a
variable in my program?

Two choices, read the file line by line (using std::getline) and
tokenise the line or read the file token by token (>>).

The fist is better if the input format varies (inconsistent use of white
space for example).
 
M

mlt

Ian Collins said:
mlt said:
I have a file containing:

w = 23
h = 34
S = 2

I would like to read this text file into variables in a program like:
std::string file = "args.txt";
std::ifstream infile;
infile.open (&file[0]);

int w,h,S;

w = infile.??
h = infile.??
S = infile.??


But how do I read the value on each line in the file after the '=' to a
variable in my program?

Two choices, read the file line by line (using std::getline) and
tokenise the line or read the file token by token (>>).

The fist is better if the input format varies (inconsistent use of white
space for example).

Ok before I look into that, are there any better way to pass multiple
runtime arguments to an application?
 
M

mlt

mlt said:
Ian Collins said:
mlt said:
I have a file containing:

w = 23
h = 34
S = 2

I would like to read this text file into variables in a program like:
std::string file = "args.txt";
std::ifstream infile;
infile.open (&file[0]);

int w,h,S;

w = infile.??
h = infile.??
S = infile.??


But how do I read the value on each line in the file after the '=' to a
variable in my program?

Two choices, read the file line by line (using std::getline) and
tokenise the line or read the file token by token (>>).

The fist is better if the input format varies (inconsistent use of white
space for example).

Ok before I look into that, are there any better way to pass multiple
runtime arguments to an application?

I am using Visual studio.
 
R

Rui Maciel

mlt said:
I have a file containing:

w = 23
h = 34
S = 2

But how do I read the value on each line in the file after the '=' to a
variable in my program?

In order to do that you need to define a formal grammar for the document's language. Then, based on that formal definition, basically write a couple of routines: a function that converts character sequences into tokens (known as a lexer) and another that, from a sequence of those tokens, verifies if the syntax is correct and builds data structures. It's a somewhat tedious job but thankfully there are tools (flex, bison, re2c, etc..) that are able to generate a lot of the code.

Usually you don't really need to write one, as there are quite a few general purpose libraries dedicated to that sort of stuff. If you are interested, you can take a look at a couple of libraries I've managed to pull together. They are:

- A JSON parser library, written in ISO C: https://sourceforge.net/projects/mjson/
- A INI parser library, written in C++ with the help of re2c: https://sourceforge.net/projects/minip/

I do believe that you will find the INI parser to be of some use, as it can parse the code you gave as example.


Hope this helps,
Rui Maciel
 
R

Rui Maciel

Daniel said:
If you want to use a file, then I suggest you remove the parts you don't
need. Something like this:

--in the file:
23 34 2

--in the code:
ifstream infile("args.txt");
int w, h, S;
infile >> w;
infile >> h;
inflie >> S;

You should add error code to the above of course.

That's a silly suggestion. If you need to parse a grammar then you parse the grammar. You don't go off mangling the grammar until it becomes unreadable just so it may fit a crude, broken attempt at a parser.


Rui Maciel
 
L

Lionel B

In order to do that you need to define a formal grammar for the
document's language. Then, based on that formal definition, basically
write a couple of routines: a function that converts character sequences
into tokens (known as a lexer) and another that, from a sequence of
those tokens, verifies if the syntax is correct and builds data
structures. It's a somewhat tedious job but thankfully there are tools
(flex, bison, re2c, etc..) that are able to generate a lot of the code.

Talk about using a sledgehammer to crack a nut! That's ridiculous overkill
if the OP's file format is as simple as presented.

[...]
 
R

Rui Maciel

Lionel said:
Talk about using a sledgehammer to crack a nut! That's ridiculous overkill
if the OP's file format is as simple as presented.

Overkill? Why?


Rui Maciel
 
D

Daniel T.

Daniel T. wrote:




That's a silly suggestion. If you need to parse a grammar then you parse the grammar.
You don't go off mangling the grammar until it becomes unreadable just so it may fit a
crude, broken attempt at a parser.

The OP doesn't need to parse a grammar he simply needs to "pass
multiple
runtime arguments to an application". Let's not loose focus.

More than likely, all he needs is to learn how to grab command line
arguments, but we won't know until he responds with more information.
 
R

Rui Maciel

Daniel said:
The OP doesn't need to parse a grammar he simply needs to "pass
multiple
runtime arguments to an application". Let's not loose focus.

I don't believe that's the case. The OP claimed that he wanted to import values from a text file. He also provided an example of said text file, which basically is a series of lines consisting of a label followed by an equal sign and a value. By stating that the document format consists of multiple lines containing a text label, a '=' character and a value he has already defined a grammar. It may not be BNF but it is still a grammar.

More than likely, all he needs is to learn how to grab command line
arguments, but we won't know until he responds with more information.

The OP explicitly asked how he "could read the value from each line in the file".

Nonetheless, your suggestion is very odd. If you want to get values from the command line arguments you are still faced with the problem of implementing a parser, but this time with the added difficulty of dealing with an array of null-terminated strings instead of a simple stream.


Rui Maciel
 
L

Lionel B

Overkill? Why?

Because it's an extremely simple "grammar" and to my mind hardly warrants
the full machinery (flex, bison, ...). Surely much simpler (and probably
far less time-consuming) just to tokenise and do a little error checking?

But your mileage may differ.
 
L

LR

mlt said:
I have a file containing:

w = 23
h = 34
S = 2

I would like to read this text file into variables in a program like:
std::string file = "args.txt";
std::ifstream infile;
infile.open (&file[0]);

int w,h,S;

w = infile.??
h = infile.??
S = infile.??


But how do I read the value on each line in the file after the '=' to a
variable in my program?

Firstly, I'd like to say that I like the idea of files with labeled
content. Easier to read in a year or so when you've forgotten exactly
what those numbers mean.

I'm not offering a solution, but a point of departure. I haven't tried
compiling any of the incomplete code I'm posting here. It's just an
idea. Not a very robust idea. And being more robust might be important.

Or perhaps the exact order of the data in the file is important to you,
in which case this might not be the way to go.

Class FileInfo {
typedef std::map<std::string,std::string> Map;
Map m_;
public:
..
..
.. // ctors etc
..
bool readfile(const std::string &filename) {
// this might be a ctor instead of a function
m_.clear();
// open the file and...
std::string line;
while(std::getline(infile, line)) {
std::istringstream inline(line);
std::string name;
std::string equal;
std::string value;
// should check results here...
inline >> name >> equal >> value;
// might want to check things here too.
m_[name] = value;
}
return true;
}

int getInt(const std::string &name, const int defaultValue) const {
// look up the name as the key in m_ and if we find it,
// convert the associated value to an int and return it.
// if we can't do any of that, then either return the
// default value or just fail or throw.
}

... // not to hard to do the same for other numeric
... // types if you need to.
... // If values ever are strings with whitespace you may
... // want to rewrite readfile a little.


};



....Meanwhile, in another part of the program...
class MyClass {
int w,h,s;
public:
....
MyClass(const FileInfo &f) :
w( f.getInfo("w",0) ),
h( f.getInfo("h",0) ),
s( f.getInfo("S",0) )
{}
....
};


I hope this is enough to go on. It's not a perfect idea, I'm sure there
are better ways to do it, but work out the details and I suspect this
will do some reasonable amount of work for you.

And if you do decide to go with a command line, then you can always
adapt the idea, 'programname /h 34 /w 23 /S 2' by taking the arguments
an putting them into a FileInfo class. Maybe FileInfo isn't a great
name. Make some member function in FileInfo like,
void insert(const std::string &name, const std::string &value) { ... }
and you'll be able to reuse the example ctor I wrote for MyClass.

I don't think it's much of a leap to extend the idea for multiple
classes and being able to write what you read if you need to.

However, it's not entirely clear from your post what you want to
accomplish. If, for example, you have to use the particular format you
posted, so I'm not sure this is the kind of thing you need. If not,
then if you'll ask more specific questions, then you'll probably get
better answers.

HTH.

LR
 
R

Rui Maciel

Lionel said:
Because it's an extremely simple "grammar" and to my mind hardly warrants
the full machinery (flex, bison, ...). Surely much simpler (and probably
far less time-consuming) just to tokenise and do a little error checking?

Yes, you are right. Using flex and bison for that grammar would be overkill, not to mention frightening.


Rui Maciel
 
R

Rui Maciel

Daniel said:
There are tons of tutorials on the 'net for how to deal with command
line arguments, and none of them require "flex, bison, re2c, etc.." as
you suggested.

Can you point out a tutorial on "how to deal with command line arguments" in C++ that doesn't implement any type of parser?


Rui Maciel
 
M

Michael DOUBEZ

Rui said:
Can you point out a tutorial on "how to deal with command line arguments" in C++ that doesn't implement any type of parser?

Boost.Program_options

The point is that the parser is hidden in the command line argument
library. So indeed, you don't need a general parser tool but someone did
the job at one point.
 
R

Rui Maciel

Daniel said:
That will suit the OPs purpose? Sure:

int main( int argc, const char* argv[] )
{
if (argc < 4) return EXIT_FAILURE;

int w = lexical_cast<int>(argv[1]);
int h = lexical_cast<int>(argv[2]);
int S = lexical_cast<int>(argv[3]);
// use w, h, and S
}

lexical_cast can be found in boost or easily written yourself. (Again,
add error handling code as necessary.)

That code doesn't deal with command line arguments. It is nothing more than a flimsy hack that blindly tries to convert strings to ints. I seriously doubt that there is even a single decent program out there that relies on that to parse command line arguments.


Rui Maciel
 
R

Rui Maciel

Michael said:
Boost.Program_options

The point is that the parser is hidden in the command line argument
library. So indeed, you don't need a general parser tool but someone did
the job at one point.

Exactly. Even Boost.Program_options relies on a parser to handle the command line arguments, just like any library that imports data from some document format. Maybe I implied a "reinvent the wheel" approach, which wasn't what I meant. The point is that whenever you need to import data, whether from a text document or the command line arguments, you rely on a parser.


Rui Maciel
 
D

Daniel T.

Daniel said:
That will suit the OPs purpose? Sure:
int main( int argc, const char* argv[] )
{
if (argc < 4) return EXIT_FAILURE;
int w = lexical_cast<int>(argv[1]);
int h = lexical_cast<int>(argv[2]);
int S = lexical_cast<int>(argv[3]);
// use w, h, and S
}
lexical_cast can be found in boost or easily written
yourself. (Again, add error handling code as necessary.)

That code doesn't deal with command line arguments. It is
nothing more than a flimsy hack that blindly tries to convert
strings to ints.

Of course it deals with command line arguments. Like any other
possible solution, it requires the command line arguments to be in a
particular format, and parses them out based on the format it
requires.
I seriously doubt that there is even a single decent program
out there that relies on that to parse command line arguments.

What does it take for you to consider a program "decent"?
Must the code that parses the command line arguments be complex for a
program to be decent? I don't think so...
 
J

Juha Nieminen

mlt said:
std::string file = "args.txt";
std::ifstream infile;
infile.open (&file[0]);

Not related to your question per se, but you can't do that. The
contents of a std::string are *not* guaranteed to be null-terminated
(and with some compilers in some systems that may very well be the
case). You are very likely to get a segmentation fault in many systems
if you do that.

The proper way is:

infile.open(file.c_str());
 
M

Michael DOUBEZ

Rui said:
The point is that whenever you need to import data, whether from a text document or the command line arguments, you rely on a parser.

At least, you rely on a structure in the text.

double a,b,c;
cin>>a>>b>>c;

Could be enough for some structure. I don't think you could call it a
parser -albeit a brittle one- in the sense of syntax analysis but it
parses the data all the same (extract token) :)

I have worked in some scientific environment where people wouldn't care
about a language and where happy enough to put rows of values in a file.
After all you can always add a tool to produce the data and ensure its
integrity.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,052
Latest member
LucyCarper

Latest Threads

Top