I'm trying to read data values from a text file and store them in a data structure. I could achieve something like this fairly simply in Java but I am unsure how to best approach the problem.
A line of data is x, y, sigma like 1.1 1.2 1.3. I know how to get the entire line into a string in c++, using getline(myFile, string) but I'm not sure if this is the correct approach or if it is, where to go from there. Is it possible to split the line then parse the split strings as double values?
My data structure looks like this:
struct datapoint {
double x;
double y;
double sigma;
double weight;
double xSquared;
double xy;
};
My questions are these:
Is there a way to parse numbers into structures, where each line of the .txt file is a struct in an array of datapoint?
If there is no direct method, are there equivalents in c++ of Java's split() and Double.parseDouble(string) methods?
Thanks.
Just reading them in with
std::cin >> x >> y >> sigma >> weight >> xSquared >> xy;
might be the easiest solution for your problem...
However, if you really need to do the splitting, have a look here: http://www.cplusplus.com/faq/sequences/strings/split/
Related
I have previously used C++, but I can definitely say I am not a pro. Not really even at coding in general. I'm trying, as much as it may not look like it. :/
My task is to create an array of structres of the type, "book_list".
the struct looks like this:
struct book_list
{
int bookNumber; string bookTitle; string bookAuthor;
string bookDescription; int bookMonth; int bookYear; int bookRating;
};
It's easy enough to create the array itself:
book_list myBookList[50];
Here's where I'm having trouble:
The program is intended to search for a .txt file. If it finds it, it will read into the array of structures all the data contained within the file. So, bookNumber with the .txt file's bookNumber, etc.
I have been looking up potential solutions all day, and I've looked into ideas such as ifstream, getline, using iterators, etc. My research has been as scattered as my brain, and I think I am a little stumped.
Please help, and if you need any further info, please let me know!
Thanks,
-Jon
You need to either read/parse each entry separately or read the entire file in then parse it. Since you're storing all the structs in memory anyway, the latter is probably fine if you don't want to bother with reading one at a time, but for educational purposes, you might want to try reading one at a time. Maybe separate by lines?
Then you need a way to parse the entries. There's no one way to do this, but the easiest is probably to use a JSON-formatted text file, mainly because there are libraries that can use it and tools that can help visualize it. JSON lets you represent dictionaries, arrays, strings, numbers, and booleans. You can either do this manually without much effort since you don't have anything fancy like nested structures, or you can use a library like this to parse JSON for you: https://github.com/DaveGamble/cJSON
(which is in C, will have to link with C++ if you want to use C++)
Assuming that the question may be formulated as:
can you give me a tiny programming example that can kickstart my exercise:
program p:
#include <iostream>
using namespace std;
int main() {
int num;
string buf;
while (true) {
cin >> num; if (cin.eof()) break;
cin >> buf; if (cin.eof()) break;
cout << "num is: " << num << " buf is: " << buf << endl;
}
}
text file t.txt
1
one
2
two
you can run
p < t.txt
and see that the output is what you probably expected.
Now of course change cin >> num; into cin >> booklist[0].bookNumber; etc. and your exercise will be on the right track.
Use <stdio.h> for FILE.
char *name;
FILE *file;
name = "database.txt";
file = fopen(name,"w+");
book_list myBookList[50];
While writing use this.
book_list newRecord;
newRecord.bookNumber = 0;
//other assignments
fseek(file,0,SEEK_END);
fwrite(&newRecord,sizeof(book_list),1,file);
fclose(file);
While reading use below.
file = fopen(name,"r+");
book_list record;
fseek(file,0,SEEK_SET);
int i=0;
while(true){
fread(&record,sizeof(book_list),1,file);
if(feof(file))
break;
myBookList[i].bookNumber = record.bookNumber;
//other assignments
i++;
}
fclose(file);
Note: I'm not sure this is working properly with string class.I have used this with char[SIZE] and strcpy. My suggestion is try this first with built-in types like int, float, char etc.
I'm quite new to reading and writing to files. But basically, I have an assignment where part of it requires me to determine whether a line from a file is an integer or double.
This is the part of the assignment I need help on:
Open the text file and read it's contents one line at a time. Determine if the line read from the file is a double or an integer. You are to place the integers in a vector called iNumbers and the doubles in a vector called dNumbers. The vector iNumbers should hold pointers to the Integer class and dNumbers should hold pointers to the Double class. When you add a value to one of the vectors you should use new and call the constructor that takes a string. For example:
iNumbers.push_back(new Integer("12.23"));
Sample of the file:
12
20
80.5
99.345
70
From what I understand, I think I write code that will read the lines in the file and if they have a "." then those will be doubles, but I am not sure as how to start with that.
Any help as to how I should get started would be very appreciated and thanks in advance.
Beware, in C++ (and not only C++), 1e4 is also double (with value of 10000).
If this is not allowed in the task (and finding . in the number is sufficent), then I would create std::ifstream for the file, read from it using std::getline into a std::string s, then in the string I would s.find('.') and if it is to be found (the result of find != s.npos, pass it into dNumbers as new Double(s), if such constructor exists for your class.
To be pedantic, in the general case the best way to figure out whether or not a string is an integer is to try to convert it to an integer without any error or leftover characters.
Here is a very simple method to do just that (for any type):
template <typename T>
T string_to( const std::string& s )
{
T value;
std::istringstream ss( s );
ss >> value >> std::ws;
if (!ss.eof()) throw std::invalid_argument("T string_to()");
return value;
}
You can now test for any standard integer vs double:
int n;
double d;
try {
n = string_to <int> ("12.3");
// it's an int
}
catch (...) {
try {
n = string_to <double> ("12.3");
// it's a double
}
catch (...) {
// it is neither integer nor double
}
}
If desired, you can specialize the int types to handle things like "0xF3" by unsetting the basefield: ss.unsetf(std::ios::basefield);.
Hope this helps.
Here is a straightforward way you could accomplish this task:
read from the stream using std::getline to a std::string
use std::stof and std::stoi with this string as the parameter to determine the type - if they throw std::invalid_argument or std::out_of_range, conversion could not be done
push_back to one of the arrays, depending on which type was
Glad to see that we are in the same class...
There is more to the assignment that you left out. We have our double.cpp and our integer.cpp files that include constructors that take a string as a parameter if you did your program correctly, that is. So the iNumbers.push_back(new Integer("12.23")); is basically saying "iNumbers" - the name of the vector, ".push_back" - the function that puts the string value onto the stack, "new Integer" - allocating memory for the type Integer, and "12.23" - the actually double value that was used as an example in the form of a string taken from the .txt file.
What you need to do is look through his lecture slides that include the content about I/O files and you should be fine. We even did an example in class.
As far as your basic question about integer and double types, its very simple and I have no idea how you got through the past assignments without knowing the difference, an integer does not have a decimal point and a double does. Now there may be a more complicated definition for an integer and a double type but for Stevenson's class this is the only thing you should think about. Forget what you learned in your math class about integers. The definition is not the same for this class.
Best of luck...
See you in class
-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>()};
I need to parse a string containing a comma separated list of objects, like a="1,2,3,4,5".
I also want the object type to be interchangeable, it is defined by typedef type val_type.
My approach is
vector<val_type> v();
istringstream iss(a); string x; val_type y;
while (getline(iss, x, ',') && istringstream(x) >> y) v.push_back(y);
Which works, but apparently runs much slower (about 5x) compared to using atoi() assuming the object type is an integer.
while (getline(iss, x, ',')) v.push_back(atoi(x.c_str()));
Is that huge difference in performance to be expected? Any clever way to get around this issue?
Okay, so i have a fairly annoying problem, one of the applications we use hdp, dumps HDF values to a text file.
So basically we have a text file consisting of this:
-8684 -8683 -8681 -8680 -8678 -8676 -8674 -8672 -8670 -8668 -8666
-8664 -8662 -8660 -8657 -8655 -8653 -8650 <trim... 62,000 more rows>
Each of these represent a double:
E.g.:
-8684 = -86.84
We know the values will be between 180 -> -180. But we also have to process around 65,000 rows of this. So time is kinda important.
Whats the best way to deal with this? (i can't use Boost or any of the other libraries, due to internal standards)
As you wish, as an answer instead... :)
Can't you just use standard iostream?
double val; cin >> &val; val/=100;
rinse, repeat 62000*11 times
I think I'd do the job a bit differently. I'd create a small sorta-proxy class to handle reading a value and converting it to a double:
class fixed_point {
double val;
public:
std::istream &read(std::istream &is) {
is >> val; val /= 100.0; return is;
}
operator double() { return val; }
friend std::istream &operator>>(std::istream &is, fixed_point &f) {
return f.read(is);
}
};
Using that, I could read my data a bit more cleanly. For example:
std::vector<double> my_data;
std::copy(std::istream_iterator<fixed_point>(infile),
std::istream_iterator<fixed_point>(),
std::back_inserter(my_data));
The important point here is that operator>> doesn't just read raw data, but extracts real information (in a format you can use) from that raw data.
There are other ways to do the job as well. For example, you could also create a derivative of std::num_get that parses doubles from that file's format. This is probably the way that's theoretically correct, but the documentation for this part of the library is mostly pretty poor, so I have a hard time advising it.