istringstream not outputting correct data - c++

I am having trouble getting istringstream to continue in while loop shown below. The data file is shown below also. I use getline from Input file to get the first line and put it in a istringstream lineStream. It passes through the while loop once, then it reads in the second line and goes back to the beginning of the loop and exits rather than continue through the loop. I have no clue why, if anyone could help I would thankful.
EDIT: The reason I have this while loop condition is because the file may contain lines of erroneous data. Therefore, I want to make sure the line I am reading in has the proper form shown below in the data file.
while(lineStream >> id >> safety){//keeps scanning in xsections until there is no more xsection IDs
while(lineStream >> concname){//scan in name of xsection
xname = xname + " " +concname;
}
getline(InputFile, inputline);//go to next xsection line
if(InputFile.good()){
//make inputline into istringstream
istringstream lineStream(inputline);
if(lineStream.fail()){
return false;
}
}
}
Data FILE
4 0.2 speedway and mountain
7 0.4 mountain and lee
6 0.5 mountain and santa

In the presented code, …
while(lineStream >> id >> safety){//keeps scanning in xsections until there is no more xsection IDs
while(lineStream >> concname){//scan in name of xsection
xname = xname + " " +concname;
}
getline(InputFile, inputline);//go to next xsection line
if(InputFile.good()){
//make inputline into istringstream
istringstream lineStream(inputline);
if(lineStream.fail()){
return false;
}
}
}
… the inner declaration of lineStream declares a local object, which ceases to exist when the execution passes out of that block, and which doesn't affect the stream used in the outer loop.
One possible fix is to invert the code a little bit, like this:
while( getline(InputFile, inputline) )
{
istringstream lineStream(inputline);
if(lineStream >> id >> safety)
{
while(lineStream >> concname)
{
xname = xname + " " +concname;
}
// Do something with the collected info for this line
}
}

Related

Simple casting conversion on C++

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;

Need help in tokenizing a text file and storing in vector

I am reading from a text file that looks like this:
1|Pink Floyd
2|Genesis
3|Einaudi
4|Melanie C
I have a vector artistVector to store the ID (integer), and the Artist Name char(100).
I am trying to parse the text file and store the parsed ID and Name like this:
artistVector[0] = 1
artistVector[1] = Pink Floyd
artistVector[2] = 2
artistVector[3] = Genesis
artistVector[4] = 4
artistVector[5] = Einaudi
artistVector[6] = 6
artistVector[7] = Melanie C
But for some reason, my code after Pink Floyd is not working with my sqlite insert record function.
static vector<string> readFile(vector<string> artVec, ifstream &iFile) //Read the file into the vector function definition
{
vector<string> vector;
string line;
if (iFile.is_open()) {
while (!iFile.eof()) {
// read an item using | as a delimiter
//getline(artist, line, '|');
getline(iFile, line, '|');
vector.push_back(line);
getline(iFile, line, '\n');
vector.push_back(line);
getline(iFile, line, '\n');
vector.push_back(line);
}
}
else {
cout << "Unable to open file";
}
return vector;
}
int main() {
vector<string> artistVector;
ifstream artistFile("artist.txt"); //Input file
artistVector = readFile(artistVector, artistFile);
std::string sqlArtistInsert[8];
for (int i = 0; i < artistVector.size(); i++) {
sqlArtistInsert[i] = artistVector[i];
}
cout << sqlArtistInsert[0] << endl;
cout << sqlArtistInsert[1] << endl;
cout << sqlArtistInsert[2] << endl;
system("pause");
return 0;
}
My output looks like this:
1
Pink Floyd
2
Notice the white space between Pink Floyd and 2? aka sqlArtistInsert[1] & sqlArtistInsert[2]
please take a look at my code below and any help would be much appreciated!
Problems I see:
Problems in while loop
while (!iFile.eof()) {
// read an item using | as a delimiter
//getline(artist, line, '|');
getline(iFile, line, '|');
vector.push_back(line);
getline(iFile, line, '\n');
vector.push_back(line);
getline(iFile, line, '\n');
vector.push_back(line);
}
The last call to getline will read an additional line of text. When the loop is executed the first time,
line will be assigned "1" in the first call to getline.
line will be assigned "Pink Floyd" in the second call to getline.
line will be assigned "2|Genesis" in the third call to getline.
I am sure that is not your intention. Remove the third call to getline in the loop.
The other problem is that you will end up storing more items in vector than there are in the file. See Why is iostream::eof inside a loop condition considered wrong? for a more in-depth explanation. Your loop needs to be something like:
while (getline(iFile, line, '|')) {
vector.push_back(line);
getline(iFile, line, '\n');
vector.push_back(line);
}
Insufficient size of sqlArtistInsert in main
With your current size of 8, the program was using memory beyond the valid limits due to the problems in the while loop. With the while loop fixed, that should not be a problem any more.
To be safe, I would use:
for (unsigned i = 0; i < artistVector.size() && i < 8; i++) {
sqlArtistInsert[i] = artistVector[i];
}

Use stringstream to read line of varying elements

I have a file I need to read in that looks somethig like this:
1 2.23 Dove Body Wash
3 .50 Bic Pen
11 12.99 Tombstone Pizza
Where the field with the names of the products can have either only one word (Shampoo) or any number of words (Big mama's homestyle steak fries). The input file can also have blank lines, which I just need to skip over.
So what I have right now looks like this (using getline and stringstream):
This struct:
struct CartItem {
string itemName;
int quantity;
double pricePerItem;
CartItem();
CartItem(string name, int qty,double price);
};
and then this code.
while (getline(itemList, inputline)) { //itemlist is my ifstream, inputline is a string declared.
ss.clear();
ss.str(inputline);
ss >> item.quantity >> item.pricePerItem >> item.itemName;
string word;
while (ss >> word)
{
item.itemName += " " + word;
}
if (ss.fail()) {
continue;
}
else
shoppingList.push_back(item);
}
sortItems(shoppingList, sortedList);
printReport(sortedList);
but it's not working (just crashing). If I replace the while(ss >> word) fragment with if(ss>>word) it works but I only get the second string from the file. Can anyone see what I'm doing wrong here?
You should provide more details, e.g. what "just crashing" means. However, I think you have problem with your logic.
ss >> word will be called on the final check in the while loop, when ss is already out of words, thus the word will fail to be extracted to word when the while loop exits, setting ss's fail bit. Now, ss.fail() will always be true and you will never add items to your list.
I am guessing that you later rely on shoppingList having at least one item and this is the crash.
Try changing:
while (ss >> word)
{
item.itemName += " " + word;
}
to:
while (ss.good())
{
ss >> word;
item.itemName += " " + word;
}

Can't output my whole file, premature exit by inputFile.eof()

if(inputFile.is_open()){
while(!inputFile.eof()){
getline(inputFile, line);
ss << line;
while(ss){
ss >> key;
cout << key << " ";
lineSet.insert(lineNumber);
concordance[key] = lineSet;
}
lineNumber++;
}
}
For some reason, the while loop is kicking out after the first iteration and only displays the first sentence of my input file. The rest of the code works fine, I just can't figure out why it thinks the file has ended after the first iteration.
Thanks
Firstly you should be reading the file without using eof , as πάντα ῥεῖ notes (see here for explanation):
while( getline(inputFile, line) )
{
// process the line
}
Note that the preceding if is not necessary either.
The main problem , assuming ss is a stringstream you defined earlier, comes from the logic:
ss << line;
while(ss){
// stuff
}
The while loop here only exits when ss fails. But you never reset ss to be in a good state. So although your outer loop does read every line of the file, all of the lines after the first line never generate any output.
Instead you need to reset the stringstream each time:
ss.clear();
ss.str(line);
while (ss) {
// stuff
}

Four variable file I/O C++ into hash table for processing

I have a problem with C++ File input.
I have a file with n lines that each lines contains 4 variables. I need them read them into a hash table that I created. My problem is that I can't read the file correct way.
For example here the input file variables:
line id cont uniq-number Band
0 10 B 02020213456 DaftPunk
1 11 A 02030213456 Dazy
and so on..
The main problem is to read each variable in line until file EOF.
So I need read in each line these variables id, cout, uniq-number and band and while it is reading put these data inside a hash table to process them even further in C++.
Example
cout << "File" << endl;
int date,id;
string group,line,ch;
datar d;
hasher h1;
ifstream inFile;
inFile.open("file.txt");
while (getline (inFile,line))
{
// "reads" file each variable
inFile >> id >> ch >> date >> group;
//add these variable in line one to first hash line
d.id = id;
d.data = ch;
d.date= date;
d.group = group;
h1.add(d);
//must repeat until file EOF for each line
}
inFile.close();
In this code,
while (getline (inFile,line))
{
// "reads" file each variable
inFile >> id >> ch >> date >> group;
//add these variable in line one to first hash line
d.id = id;
d.data = ch;
d.date= date;
d.group = group;
h1.add(d);
//must repeat until file EOF for each line
}
the getline reads a line.
Then the loop body reads items from the next line.
Instead of that
inFile >> id >> ch >> date >> group;
do e.g.
istringstream linestream( line );
linestream >> id >> ch >> date;
getline( linestream, group );
The last getline in order to handle possible spaces in a name.
This assumes that the name is last on the line, as it currently is, and it assumes that it's not the case that every second line should be ignored (i.e., that that was bug).
It's also a good idea to add failure checking.
If a stream operation fails then the stream enters a failure state, and you can check that via the member function .fail().