Reading variables from text file - c++

I have a problem in c++, and I hope that some expert here could help me.
the problem is, there is a .txt file, that has some information. I want to write a program that uses this information.
the .txt file will be like this:
variable 1: 711
variable 2: [8 5 6 11]
variable 3: xyz zyx yyy
the program should read the values from the file and then use them, any idea how to do it ?!!
/* UPDATE */
what should be done is to read from the text file the numerical values, only the numerical values of the variables, and then use these values in the real program.
for example the value of variable 1 is read and put to a variable x, then in the program we may define
int y=7*x ;
I know how to read a file, but what I don't know is how to read specific values of the variables.
Basically the program should read the file, recognize the name of the variable, get the value, and then use it.
many thanks

Looks like you want to have some configuration-like file to store some information for your program to use. There are many implementations of config-files management (read, retrieve, store, save). I stick to small and convenient libconfig : http://www.hyperrealm.com/libconfig/
It supports integer, floating-point and boolean variables, and arrays, lists and enclosed sections also.

I think it's implicit in your question that the variables could have different types, such as numbers, arrays or strings. In that case, you must decide whether to use say boost::any<> or boost::variant<>, or create your own variable type ala:
struct Var
{
enum { Double, String, Array } Type;
Type type_;
double double_;
std::string string_;
std::vector<double> array_;
Var(Type t) : type_(t), double_(0) { } // empty double/string/array
Var(double d) : type_(Double), double_(d) { }
Var(const std::string& s) : type_(String), string_(s) { }
...
};
Alternatively, you could use C++'s inbuilt polymorphism and have a base class and a derived class for each real-world data type. It might even be enough for you to always store the textual representation, and store everything in a std::string. However you do it, let's say you store values in a type named "Type".
It seems the name of the variables is to be specified on the left of the colon. If you know corresponding variables will be hard-coded in your program, then you can then set those pre-existing variables to the values on the right. Otherwise, you need to create variables associated with those identifier names dynamically: this can be done with a std::map<std::string, Type> keyed on identifier. You could populate it as in:
std::map<std::string, Type> variables;
variables["age"] = Type(28);
variables["name"] = Type("Fred");
For parsing the actual text file, you can use iostreams. Read a line at a time ala:
std::string line;
while (getline(cin, line))
{
std::string::pos n = line.find(':');
if (pos != std::string::npos)
{
std::string identifier = line.substr(0, n - 1);
Type var;
{
// try parsing it as a number...
std::istringstream iss = line.substr(n + 1);
char c;
double d;
if (iss >> d && !(iss >> c))
var = d;
}
{
// try parsing it as an array...
std::istringstream iss = line.substr(n + 1);
var.clear(Array);
double d;
if (iss >> c && c == '[')
while (iss >> d)
result.array_.push_back(d);
if (iss && iss >> c && c == ']' && !(is >> c))
// parsed successfully as an array - use "result"
}
{
// it's a string...
var = line.substr(n + 1);
}
You should try to make a start on this and ask for specific help where you get stuck.
Note: you may find it easier to get a working (albeit slow) program meeting this requirement in a language such as Ruby, python or perl.

Related

Read from a file in C++

4;
Spadina;76 156
Bathurst;121 291
Keele;70 61
Bay;158 158
This is what file contains in it. I need to read them and save them into variables.
4 is for dynamic memory allocation. 4 means there are 4 stations.
Spadina, Bathrust, etc.. they are station names. first number, which comes right after station names, is number of student passes and the second number is number of adult pass.
So, basically I have 4 variables and they are;
int numberOfStation;
int studentPass;
int adultPass;
string stationName;
I spent 4 hours but still cannot read the file and save it into variable
Thank you.
A possible solution is to read every line with e.g. std::getline then parse each such line string. You'll use the appropriate methods of std::string to search inside it (with find) and split it (with substr). You might also access some individual character in that string using at or the [] operator of std::string; alternatively, you might perhaps parse each line -or relevant parts of them- using std::istringstream (I am not sure it is appropriate in your case). You might be interested by std::to_string...
An important thing is to define exactly (not only thru examples) the possible acceptable inputs. You could for example use some EBNF to formalize that. You should probably care about character encoding (try first by assuming a simple single-byte encoding like ASCII, then later consider UTF-8 if your system uses it).
For example, can the station names (I guess you talk about subway stations) contain digits, or spaces, or underscores, or commas, etc.... ? Could they be French names like Hôtel de Ville (a metro station in central Paris) or Saint-Paul or Bourg-La-Reine (where I am), or Russian names like Молодёжная in Moscow? (I guess that station names in Tokyo or in Jerusalem might be even funnier to parse).
BTW, explicitly entering the number of entries (like your initial 4) is very user-unfriendly. You could have some lexical conventions and e.g. use some tagging or separators.
At last, you might want to keep the information for every travel. Then you'll probably need to define some struct or class (not simply four scalar variables). At that point your program is becoming more interesting!
First group your variables in struct.
struct MyStruct
{
int studentPass;
int adultPass;
string stationName;
};
Now read size of struct in file and allocate it dynamically
MyStruct *p;
s >> N;
p = new MyStruct[N];
Now in for loop you read string with delimiter ';' and other two vars are ints
for (int i = 0; i < N; i++)
{
getline(s, p[i].stationName, ';');
s >> p[i].studentPass >> p[i].adultPass;
}
Where var s is istream type of variable with flag std::in
I recommend that you create a struct to hold your stations:
struct station{
string _stationName;
int _studentPass;
int _adultPass;
};
Then create an operator to use with your struct (props to Sly_TheKing for the getline idea):
std::istream& operator>>(std::istream& is, station& rhs){
getline(is, rhs._stationName, ';');
is >> rhs._studentPass >> rhs._adultPass >> ws;
return is;
}
Say that your ifstream is called foo. You can read these into a vector like this:
foo.ignore(numeric_limits<streamsize>::max(), '\n');
vector<station> bar{istream_iterator<station>(foo), istream_iterator<station>()};

Reading comma separated data from string into struct, ignoring certain fields

About the data:
Fields are separated by comma ','
It is always a certain number of fields (in my case 33)
Fields are always in the same order
The data is of different types, represented in ASCII. The types are known to me
Some fields are always empty, and some are always to be ignored (not useful data)
Example of data:
AnIdentifier,1,G,2014-10-01,11:00,,,3,7555,1,14535,1 .. etc
I am wondering what is the best way to read this data into a struct, in a C++ way. I used sscanf earlier, but I thought the format-parameter of the call got rather big and messy.
I also tried splitting the string into tokens in a vector, before setting the values in the struct one by one with values from the vector, but then I didn't have the nice automatic data conversion.
I saw an example of overloading the >> operator in the struct:
struct MyDataStruct
{
std::string Id;
char D;
char S;
std::string Date; // Preferably these could be combined
std::string Time; // to a time_t?
bool Running;
int Runtime;
...
...
friend std::istream &operator>>(std::istream &is, MyDataStruct &ds) {
return is >> Id >> D >> S >> Date >> Time >> Running >> Runtime ...
}
}
My C++ knowledge is limited (used to C#), so I started to struggle when there were fields I wanted to ignore while reading into the struct. Say there are 5 fields in is after reading into Time that I wish to skip before reading into Running.
And say I wished to represent the timestamp by a time_t instead of the two strings Date and Time (the way they are represented in the received data), could this be accomplished directly in the operator overload while reading into the struct?

reading formatted input using C++ streams

When using stdio.h, I can easily read certain kinds of formatted input like this:
FILE* fin = fopen(...);
fscanf(fin, "x = %d, y = %d", &x, &y);
The great thing about this is that I don't really have to worry about how many spaces there are between the character 'x' and the following '=', and other minor details.
In C++ it appears to me as though,
ifstream fin(...);
string s;
fin >> s;
may result in s being "x" or "x=", or even "x=12" depending on the spacing of the input.
Is there a convenient way to get behavior similar to scanf/fscanf using iostream/fstream?
This is actually surprisingly easy, given a prerequisite. I have these three functions that I stick in a header somewhere. These allow you to stream in character literals, and string literals. I've never quite understood why these aren't standard.
#include <iostream>
//These are handy bits that go in a header somewhere
template<class e, class t, int N>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, const e(&sliteral)[N]) {
e buffer[N-1] = {}; //get buffer
in >> buffer[0]; //skips whitespace
if (N>2)
in.read(buffer+1, N-2); //read the rest
if (strncmp(buffer, sliteral, N-1)) //if it failed
in.setstate(std::ios::failbit); //set the state
return in;
}
template<class e, class t>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, const e& cliteral) {
e buffer(0); //get buffer
in >> buffer; //read data
if (buffer != cliteral) //if it failed
in.setstate(std::ios::failbit); //set the state
return in;
}
//redirect mutable char arrays to their normal function
template<class e, class t, int N>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, e(&carray)[N]) {
return std::operator>>(in, carray);
}
Given those, the rest is easy:
in>>'x'>>'='>>data.first>>','>>'y'>>'='>>data.second;
Proof here
For more complex situations, you probably want to use std::regex or boost::regex, or maybe a real lexer/parser.
like you specify format in fscanf/scanf using %xx you can specify format using stream manipulators as detailed in this tutorial -
http://www.tenouk.com/Module18.html
very comprehensive. stream manipulator is near the bottom of the page.
The short answer is "no".
A slightly longer answer is "You can probably build something that does that". For example, you could read the line of text, and then use a suitable "replace spaces with empty string" type function. Or perhaps something like this:
int x, y;
string s;
getline(cin, s, '=');
cin.get(); // Get rid of =
cin >> x;
getline(cin, s, '=');
cin >> y;
Alternatively, using cin.ignore to skip things (since the string reading is not really useful uness you want to know that 'x' and 'y' are actually 'x' and 'y'=:
int x, y;
cin.ignore(1000000, '='); // Skip up to a '='
cin >> x;
cin.ignore(1000000, '='); // Skip up to a '='
cin >> y;
This will "break" if someone enteres over 100k characters without an = sign, and there is need for error checking to see that "garbage" isn't coming in - just like fscanf does. if (cin >> x) would take care of the "detect that something went wrong, but you need to then do something sensible with the fact that it's gone wrong, which I'm not sure of right now...
Of course, since C++ supports (nearly) all of C, you can of course always use whatever members of the <cstdio> functions that you would like to use, as well. [And in at least some cases, they are actually a bit better].

string input, how to tell if it is int?

I am writing a program that converts a parathensized expression into a mathematical one, and evaluates it. I've got the calculation bit written already.
I am using a stack for the operands, and a queue for the numbers. Adding operands to the stack isn't an issue, but I need to identify whether the input character is an integer, and if so, add it to the queue. Here's some code:
cout << "Enter the numbers and operands for the expression";
string aString;
do
{
cin >> aString
if (aString = int) // function to convert to read if int, convert to int
{
c_str(...);
atoi(...);
istack.push(int);
}
}
That's where I'm stuck now. I know I'm going to have to use c_str and atoi to convert it to an int. Am I taking the wrong approach?
Use the .fail() method of the stream.
If you need the string too, you can read to a string first, then attempt to convert the string to an integer using a stringstream object and check .fail() on the stringstream to see if the conversion could be done.
cin >> aString;
std::stringstream ss;
ss << aString;
int n;
ss >> n;
if (!ss.fail()) {
// int;
} else {
// not int;
}
I'll probably get flamed for this by the C++ purists.
However, sometimes the C++ library is just more work than the C library. I offer this
solution to C developers out there. And C++ developers who don't mind using some of the
features of the C library.
The whole check and conversion can be done in 1 line of C using the sscanf function.
int intval;
cin >> aString
if (sscanf(aString.c_str(), "%d", &intval)){
istack.push(intval);
}
sscanf returns the number of input arguments matched and assigned. So in this case, it's looking for one standard signed int value. If sscanf returns 1 then it succeeded in assigning the value. If it returns 0 then we don't have an int.
If you expect an integer, I would use boost::lexical_cast.
std::string some_string = "345";
int val = boost::lexical_cast<int>(some_string);
If it fails to cast to an integer, it will throw. The performance is pretty reasonable, and it keeps your code very clean.
I am unaware of any non-throwing version. You could use something like this, though I usually try to avoid letting exceptions control program flow.
bool cast_nothrow(const std::string &str, int &val) {
try {
val = boost::lexical_cast<int>(str);
return true;
} catch (boost::bad_lexical_cast &) {
return false;
}
}
Edit:
I would not recommend your integer validation checking for structure like you described. Good functions do one thing and one thing well.
Usually you'd want a more formal grammar parser to handle such things. My honest advice is to embed a scripting language or library in your project. It is non-trivial, so let someone else do the hard work.
If I actually tried to implement what you propose, I would probably do a stack based solution keeping the parenthesis levels at their own stack frame. The simplest thing would just be to hard code the simple operators (parenthesis, add, sub, etc) and assume that the rest of everything is a number.
Eventually you'd want everything broken down into some expression type. It might look something like this:
struct Expression {
virtual ~Expression() {}
virtual float value() const = 0;
};
struct Number : public Expression {
virtual float value() const {return val;}
float val;
};
struct AdditionOper : public Expression {
virtual float value() const {return lhs->value() + rhs->value();}
boost::shared_ptr<Expression> lhs;
boost::shared_ptr<Expression> rhs;
};
I'd start by parsing out the parenthesis, they will determine the order of your expressions. Then I'd split everything based on the numerical operands and start putting them in expressions. Then you're left with cases like 3 + 4 * 6 which would require some some care to get the order of operations right.
Good luck.
You can either run your function that converts a string representation of a number to a double and see if there's an error, or you can look at the contents of the string and see if it matches the pattern of a number and then do the conversion.
You might use boost::lexical_cast<double>() or std::stod() (C++11) where errors are reported with an exception, or istringstream extractors where the error is reported by setting the fail bit, or with C conversion functions that report errors by setting the global (thread local, rather) variable errno.
try {
istack.push_back(std::stod(aString));
} catch(std::invalid_argument &e) {
// aString is not a number
}
or
errno = 0;
char const *s = aString.c_str();
char *end;
double result = strtod(s,&end);
if(EINVAL==errno) {
// the string is not a number
} else {
istack.push_back(result);
}
An implementation of the second option might use a regex to see if the string matches the pattern you use for numbers, and if it does then running your conversion function. Here's an example of a pattern you might expect for floating point values:
std::regex pattern("[+-]?(\d*.\d+|\d+.?)([eE][+-]?\d+)?");
if(std::regex_match(aString,pattern)) {
istack.push_back(std::stod(aString));
} else {
// aString is not a number
}
Also, this probably doesn't matter to you, but most any built in method for converting a string to a number will be locale sensitive one way or another. One way to isolate yourself from this is to use a stringstream you create and imbue with the classic locale.
I guess the C++ (no boost) way would be this :
do
{
std::stringstream ss;
std::string test;
cin >> test;
ss << test;
int num;
if (ss >> num) // function to convert to read if int, convert to int
{
std::cout << "Number : " << num << "\n";
}
}while(true); // don't do this though..
Can you not use ctype.h http://www.cplusplus.com/reference/clibrary/cctype/. I have used this before and did not get into trouble.
Especially if you're doing base-10 input, I find the most blatant thing to do is read the string, then check that it only contains valid characters:
string s;
cin >> s;
if(strrspn(s.c_str(), "0123456789")==s.length()){
//int
} else{
//not int
}

Converting/parsing pointer strings and doubles

Assignment:
Read in info from text file (done)
Retrieve only parts of text file using substr method (done)
Store info into instance variables (need help)
Here is the code I am having trouble with:
string* lati;
lati = new string(data.substr(0, data.find_first_of(",")));
double* latDub;
latDub = new double(atof((char *)lati));
this->latitude = *latDub;
I need to store the latitude into the instance variable latitude.
The variable data is the read-in text file.
this->latitude is declared as a double.
I have tested and the variable lati is the correct value, but once I try to convert it into a double the value changes to 0 for some reason. I am specifically supposed to use the atof method when converting!
(char *)lati doesn't do what you think it does. What you're clearly trying to do there is get the char sequence associated with lati, but what you're actually doing is just squeezing a string* into a char* which is all kinds of bad.
There's a member function on std::string that will give you exactly what you want. You should review the documentation for string, and replace (char *)lati with a call to that function.
Why your code compiles, but gives meaningless results has already been explained by adpalumbo. There are two fundamental problems in your code leading to that error, on which I want to expand here.
One is that you use a C-style cast: (T)obj. Basically, that just tells the compiler to shut up, you know what you are doing. That is rarely ever a good idea, because when you do know what you are doing, you can usually do without such casts.
The other one is that you are using objects allocated dynamically on the heap. In C++, objects should be created on the stack, unless you have very good reasons for using dynamic objects. And dynamic objects are usually hidden inside objects on the stack. So your code should read like this:
string lati(data.substr(0, data.find_first_of(",")));
double latDub = /* somehow create double from lati */;
this->latitude = latDub;
Of course, latDub is completely unnecessary, you could just as well write to this->latitude directly.
Now, the common way to convert a string into some other type would be streaming it through a string stream. Removing the unnecessary variables you introduced, your code would then look like this:
std::istringstream iss(data.substr(0, data.find_first_of(",")));
if( !iss >> this->latitude ) throw "Dude, you need error handling here!";
Usually you want to pack that conversion from a string into a utility function which you could reuse throughout your code:
inline double convert3double(const std::string& str)
{
std::istringstream iss(str);
double result;
if( !iss >> result )
throw std::exception("Dang!");
return result;
}
However, since the very same algorithm can be used for all types (for which operator>> is overloaded meaningfully with an input stream as the left operand), just make this a template:
template< typename T >
inline T convert3double(const std::string& str)
{
std::istringstream iss(str);
T result; // presumes default constructor
if( !iss >> result ) // presumes operator>>
throw std::exception("Dang!");
return result;
}