I've attempted to use atof() (which I think is way off) and stringstream. I feel like stringstream is the answer, but I'm so unfamiliar with it. Based on some Google searches, YouTube videos, and some time at cplusplus.com, my syntax looks like below. I'm pulling data from a .csv file and attempting to put it into a std::vector<double>:
while (file.good() )
{
getline(file,line,',');
stringstream convert (line);
convert = myvector[i];
i++;
}
If you are reading doubles from a stream (file) we can simplify this:
double value;
while(file >> value) {
myvector.push_back(value);
}
The operator>> will read from a stream into the type you want and do the conversion automatically (if the conversions exists).
You could use a stringstream as an intermediate if each line had more information on it. Like a word an integer and a double.
std::string line;
while(std::getline(file, line)) {
std::stringstream lineStream(line);
std::string word;
int integer;
double real;
lineStream >> word >> integer >> real;
}
But this is overkill if you just have a single number on each line.
Now lets look at a csv file.
This is a line based file but each value is seporated by ,. So here you would read a line then loop over that line and read the value followed by the comma.
std::string line;
while(std::getline(file, line)) {
std::stringstream lineStream(line);
double value;
char comma;
while(lineStream >> value) {
// You successfully read a value
if (!(lineStream >> comma && comma == ',')) {
break; // No comma so this line is finished break out of the loop.
}
}
}
Don't put a test for good() in the while condition.
Why is iostream::eof inside a loop condition considered wrong?
Also worth a read:
How can I read and parse CSV files in C++?
Related
I'm doing an exercise for the college and I have to compare a string added including the header <string>, and a character.
I have a text file with a few lines of data from a census, like
Alabama AL 4849377 Alaska AK 736732 Arizona AZ 6731484
I want to read the state name of each line with a string variable, but the comparison is the only thing that I am asking for, because is where I have the error.
I have this fragment of code:
struct Census{
string name;
int population, code;
};
struct States{
Census state;
};
typedef States Vector[US_STATES];
void loadCensus(ifstream & census, Vector stats){
int i=0;
string readData;
string line;
while (getline(census, line)) {
stringstream linestream(line);
while (linestream >> readData) {
if (linestream >> stats[i].state.name >>
stats[i].state.code >>
stats[i].state.population)
{
std::cerr << "Bad input on line " << i << ": " << line << std::endl;
}
stats[i].state.name=readData;
stats[i].state.code=readData;
stats[i].state.population=readData;
i++;
}
}
}
How I should convert readData to an integer to assign stats[i].state.population=readData?
I get an error in line 17 in the linestream >> readData.
You want to use the getline() function instead.
I think ita a member function of ifstream or either compare the not readData to a string ("\n") - double quotation. Or put the read data into a string and check if the sting contains a '\n'.
census >> readData will read the next word (any group of non-whitespace characters) from the input. In order to do this, it will discard all whitespace on its hunt for the next word. '\n' is whitespace, so you will never read it with the >> operator without playing games you probably don't want to play.
Instead of >>, use std::getline to read a line and then use a std::stringstream to break the line up into words.
std::string line;
while (std::getline(census, line)) {
std::stringgstream linestream(line);
while (linestream >> readData) {
statistics.state[i]=readData;
i++;
}
}
But...
I do not believe statistics.state[i]=readData; does quite what you want to do. You probably want something more like:
std::string line;
while (std::getline(census, line)) {
std::stringstream linestream(line);
if (!(linestream >> statistics.state[i].name >>
statistics.state[i].abbreviation >>
statistics.state[i].population))
{
std::cerr << "Bad input on line " << i << ": " << line << std::endl;
}
i++;
}
In this state becomes an array or vector of objects that probably looks something like
struct statestats
{
std::string name;
std::string abbreviation;
int population;
};
Breaking it down line by line
std::stringstream linestream(line);
Makes a stringstream. A string stream is a stream like cin and cout or a fstream, but it contains a string. The main use is to buffer and build strings with the same syntax you would use on another stream. In this case we are use it to split up the line into words.
if (linestream >> statistics.state[i].name >>
statistics.state[i].abbreviation >>
statistics.state[i].population)
Needs to be handled in a few parts in a few parts. Over all it is an abbreviation of
if (linestream >> statistics.state[i].name &&
linestream >> statistics.state[i].abbreviation &&
linestream >> statistics.state[i].population)
Each stage of which reads from the linestream into a variable.
Next, the >> operator returns the stream being read, and this is used two ways in the example. The first allows chaining. The output of one >> is used as the input of the next, so if you look at >> as you would a function (and it is a function. See Stream extraction and insertion for more) you can think about it looking something like this:
linestream.read(statistics.state[i].name).read(statistics.state[i].abbreviation).read(statistics.state[i].population)
The >> syntax just makes it easier.
The next advantage you get from returning the stream is the stream can be tested to see if the stream is still good. It has a boolean operator that will return true if the stream is in a good state and can be used.
if(linestream)
{
good
}
else
{
bad
}
will enter good if the stream is open, has not reached the end of the stream, and has had no troubles reading or writing data.
Going back to our example
if (linestream >> statistics.state[i].name >>
statistics.state[i].abbreviation >>
statistics.state[i].population)
Will enter the body of the if statement if the stream successfully read all three values from the stream. Which is not what we want. Ooops. I've corrected the above code already.
if (!(linestream >> statistics.state[i].name >>
statistics.state[i].abbreviation >>
statistics.state[i].population))
will enter the body of the if if at least one value was not read for any reason and print out an error message. Normally when there is an error you will need to clear the error before continuing, but in this case we've use the whole stream and are about to discard it.
Assuming no error occurred all of the data from this line has been read and there is no need to
stats[i].state.name=readData;
stats[i].state.code=readData;
stats[i].state.population=readData;
I have a csv that I'd like to tokenize line by line with StringStream. The key is that I know apriori what the columns would look like. For example, say I know the file looks like the following
StrHeader,IntHeader
abc,123
xyz,456
I know ahead of time it is a string column, followed by an int column.
Common approach is to read the file line by line
std::string line;
stringstream lineStream;
while (getline(infile, line)) // read line by line
{
cout << "line " << line << endl;
lineStream << line;
string token;
while(getline(lineStream, token, ',')) // push into vector? this is not ideal
{
}
I know I can have 2 loops, and have inner loop tokenizes the string based on commas. Lots of sample code on stackoverflow would store the result into a vector<string>.
I don't want to do create a new vector every line. Since I know apriori what columns the file would have, can I somehow read directly into a string and int variable? Like this
std::string line;
stringstream lineStream;
while (getline(infile, line)) // read line by line
{
cout << "line " << line << endl;
lineStream << line; // DOESNT WORK - tell lineStream we have comma delimited string
string strValue;
int intValue;
lineStream >> strValue >> intValue; // SO MUCH CLEANER
// call foo(strValue, intValue);
}
The problem above is this line
lineStream << line; // DOESNT WORK - tell lineStream we have comma delimited string
From what I could tell, the above code works if the input line is space delimited, not comma delimited.
I have no control over the input. So, simply replacing the "spaces" with "commas" in the original string is not an ideal solution since I don't know if the input already has spaces.
Any ideas? thanks
You could try to only read to the delimiter with std::getline() and then put that in a string stream for conversion.
while (!infile.eof()){
std::getline(infile, strValue, ',');
std::getline(infile, line);
strstr.str(line);
strstr.clear();
int intValue;
strstr >> intValue;
foo(strValue, intValue);
}
I want to read in scores from a txt file. The scores are going into a struct.
struct playerScore
{
char name[32];
int score, difficulty;
float time;
};
the text file looks like this
Seth 26.255 40 7
as one line, where each item is followed by a tab. (Name\t time\t score\t difficulty\n)
When I begin to read in the text, I don't know how to tell the program when to stop. The scores file could be any number of lines or score entries. This is what I have attempted.
hs.open("scores.txt", ios_base::in);
hs.seekg(0, hs.beg);
if (hs.is_open())
{
int currpos = 0;
while (int(hs.tellg()) != int(hs.end));
{
hs>> inScore.name;
hs >> inScore.time;
hs >> inScore.score;
hs >> inScore.difficulty;
hs.ignore(INT_MAX, '\n');
AllScores.push_back(inScore);
currpos = (int)hs.tellg();
}
}
I'm trying to make a loop that will read in a line of code into a temp struct for the data, then push that struct into a vector of structs. Then update the currpos variable with the current location of the input pointer. However, the loop just gets stuck on the condition and freezes.
There are a multitude of ways to do this, but the following is likely what you're looking for. Declare a free-operator for extracting a single-line definition of a player-score:
std::istream& operator >>(std::istream& inf, playerScore& ps)
{
// read a single line.
std::string line;
if (std::getline(inf, line))
{
// use a string stream to parse line by line.
std::istringstream iss(line);
if (!(iss.getline(ps.name, sizeof(ps.name)/sizeof(*ps.name), '\t') &&
(iss >> ps.time >> ps.score >> ps.difficulty)))
{
// fails to parse a full record. set the top-stream fail-bit.
inf.setstate(std::ios::failbit);
}
}
return inf;
}
With that, your read code can now do this:
std::istream_iterator<playerScore> hs_it(hs), hs_eof;
std::vector<playerScore> scores(hs_it, hs_eof);
I dont think that you can just >> from your file. Do you think it will take everything till \t? :)
You can try to take for example token with strtok()
I guess it can use '\t' to split string and take for each variable via this function needed part of string
In case if it strtok() doesnt work that way i guess you can just copy till '\t' in sub-loop
You can do like this
playerScore s1;
fstream file;
file.open("scores.txt", ios::in | ios::out);
while(!file.eof()) //For end of while loop
{
file.read(s1, sizeof(playerScore));//read data in one structure.
AllScores.push_back(s1);
}
As my learning, I am trying to use c++ ifstream and its operator>> to read data from a text file using code below. The text file outdummy.txt has following contents:
just dummy
Hello ofstream
555
My questions is how to read char data present in the file into a char array or string. How to do this using the ifstream::operator>> in code below.
#include <iostream>
#include <fstream>
int main()
{
int a;
string s;
char buf[100];
ifstream in("outdummy.txt",ios_base::in);
in.operator>>(a); //How to read integer? How to read the string data.??
cout << a;
in.close();
getchar();
return 0;
}
If you want to use formatted input, you have to know in advance what data to expect and read it into variables of the according data type. For example, if you know that the number is always the fifth token, as in your example, you could do this:
std::string s1, s2, s3, s4;
int n;
std::ifstream in("outdummy.txt");
if (in >> s1 >> s2 >> s3 >> s4 >> n)
{
std::cout << "We read the number " << n << std::endl;
}
On the other hand, if you know that the number is always on the third line, by itself:
std::string line;
std::getline(in, line); // have line 1
std::getline(in, line); // have line 2
std::getline(in, line); // have line 3
std::istringstream iss(line);
if (iss >> n)
{
std::cout << "We read the number " << n << std::endl;
}
As you can see, to read a token as a string, you just stream it into a std::string. It's important to remember that the formatted input operator works token by token, and tokens are separated by whitespace (spaces, tabs, newlines). The usual fundamental choice to make is whether you process a file entirely in tokens (first version), or line by line (second version). For line-by-line processing, you use getline first to read one line into a string, and then use a string stream to tokenize the string.
A word about validation: You cannot know whether a formatted extraction will actually succeed, because that depends on the input data. Therefore, you should always check whether an input operation succeeded, and abort parsing if it doesn't, because in case of a failure your variables won't contain the correct data, but you have no way of knowing that later. So always say it like this:
if (in >> v) { /* ... */ } // v is some suitable variable
else { /* could not read into v */ }
if (std::getline(in, line)) { /* process line */ }
else { /* error, no line! */ }
The latter construction is usually used in a while loop, to read an entire file line by line:
while (std::getline(in, line)) { /* process line */ }
ifstream has ios_base::in by default. You don't need to specify it.
operator>> can be invoked directly as an operator: in >> a.
Reading strings is the same: in >> s, but the caveat is that it is whitespace-delimited, so it will read "just" by itself, without "dummy".
If you want to read complete lines, use std::getline(in, s).
Since you have elected to use C-strings, you can use the getline method of your ifstream object (not std::getline() which works with std::strings), which will allow you to specify the C-string and a maximum size for the buffer.
Based on what you had, and adding an additional buffer for the second line:
char buf[100];
char buf2[100];
in.getline(buf,sizeof(buf));
in.getline(buf2,sizeof(buf2));
in >> a;
However, as the other poster has proposed, try using the std::string and its methods, it will make your life easier.
You can read file contents and use a Finite State Machine for parsing.
Example:
void Parse(const char* buffer, size_t length);
size_t GetBufferSize();
size_t bufferSize = GetBufferSize();
char* buffer = new char[bufferSize];
std::ifstream in("input.txt");
while(in.getline(buffer, bufferSize)) {
Parse(buffer, in.gcount());
}
Alternatively, you can use a tool like Flex to write your parser.
While reading a file (ifstream), is there any way to direct it to make a new line?
For instance, I would like for THIS to happen:
myfile>>array[1]>>array[2]>>endl;
Obviously, the "endl" just isn't allowed. Is there another way to do this?
Edit---thanks for the quick responses guys!
From a text file, I'm trying to store two strings from that file into arrays and then do the same with the next line (or until I desire, using a for loop)
Using strings is important to me as it will make my future program a lot more flexible.
Several options:
You can use ignore.
myfile >> array[1] >> array[2];
myfile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Or you can read each line into as string stream
std::string line;
std::getline(myfile,line);
std::stringstream stream(line);
stream >> array[1] >> array[2];
Please note: Array indexing starts at 0.
Use std::getline to read a line into a memory stream, then get the two strings from that.
while (cin)
{
string line;
getline(cin, line);
stringstream stream;
stream << line;
stream >> array[1]>>array[2];
}
Read your two items, then call myfile.ignore(8192, '\n')
I have no idea what this question means. Here's a simple way to read all the lines of a file into a vector of strings. It might be easier to do what you want to do if you do this first.
std::vector<std::string> lines;
std::string line;
while (std::getline(myFile, line))
lines.push_back(line);
Now you can say lines[4] to get the fifth line, or lines.size() to find out how many lines there were.
This should work:
stringstream stream;
string sLine;
int iLine;
while (cin)
{
getline(cin, sLine);
stream << sLine;
stream >> data[iLine][0] >> data[iLine][1];
}
Customized version of an earlier answer.