so I was trying to utilise the istringstream to parse through a text file. The idea is to break down each line by space and based on the substring do stuff. The code works fine except for two things, it double counts last substring for each line and it seg faults when its done reading through the file. I have not used sstream before so any insight would be helpful.
file.getline(str,80);
while(!file.eof())
{
cout<<str<<endl;
istringstream iss(str);
while (iss)
{
iss >> sstr;
cout << "Substring: " <<sstr << endl;
}
file.getline(str,80);
}
The while loops should go like this:
std::string line;
while (std::getline(file, line))
{
std::istringstream iss(line);
std::string token;
while (iss >> token)
{
cout << "Substring: " << token << endl;
}
}
The getline and input operations return the stream object, which itself has a specialized conversion to bool that indicates whether the operation succeeded, and it will fail precisely when you've reached the end of the respective stream.
while !eof is almost always wrong.
Switch to a different C++ book, and tell us which one you're using now so that we may mock and warn accordingly.
while (file.getline(str,80)) {
cout<<str<<endl;
istringstream iss(str);
while (iss >> sstr) {
cout << "Substring: " <<sstr << endl;
}
}
Related
Filling an STL list with data from a text file fails.
Lexicon::Lexicon(const string &fileName) {
string tmp;
ifstream readFile;
readFile.open(fileName.c_str());
if (readFile.is_open()) {
cout << "File Is Open" << endl;
while (readFile >> tmp) {
list<string>::const_iterator i;
for (i = Words.begin(); i != Words.end(); ++i) {
Words.push_back(tmp);
}
readFile.close();
}
} else
{
cout<<"File Is NOT Open"<<endl;
}
}
string fileName = "wordsScrambled1.txt"; // in the main
Lexicon hello(fileName);
The program fails with the message "file is NOT open" and exits with code 0.
Before this question gets closed due to mcve, I wanted to point out some of the mistakes you're making. The first is obviously a path or permissions issue i.e. you are unable to open the input file. Once you get past that, you have likely made a mistake in your parsing of the file. You assume that all the characters between " " represent a word. This could be the case for all except the last word in the line. So you're better off using std::getline and parsing that with std::istringstream. Finally, like Sam pointed out in the comments section, you have a for loop that can't reasonably meet it's exit criteria before crashing. Just push_back the current element and move on to the next. Here is a quick example.
Lexicon::Lexicon(const std::string &fileName)
{
std::ifstream readFile(fileName.c_str());
if (readFile.is_open())
{
std::string line;
while (std::getline(readFile, line))
{
std::istringstream iss(line);
std::string word;
while (iss >> word)
{
Words.push_back(word);
}
}
readFile.close();
}
else
{
std::cout << "File Is NOT Open" << std::endl;
}
}
I am trying to read lines of a file (cityName, hiTemp, loTemp) into a struct array. I was able to use >> to read the first several lines until I hit a city with a space in it's name.
I then tried using getline() to read the lines, but then my while loop stopped working.
I have no clue why this would happen.
int LoadData()
{
int count = 0;
string path;
cout << "Specify the input file path: ";
ifstream inFile;
cin >> path;
inFile.open(path.c_str());
if (!inFile.is_open())
{
cout << "Error - could not open file: " << path;
return (-1);
}
else
{
while (!inFile.eof())
{
cities[count].city = "";
getline(inFile, cities[count].city);
if (cities[count].city.length() == 0)
{
break;
}
char comma;
inFile >> (cities[count].high) >> comma >> cities[count].low;
cout << cities[count].city << " " << cities[count].high << " " << cities[count].low << endl;
count++;
}
inFile.close();
inFile.clear(std::ios_base::goodbit);
return count;
}
}
while (!inFile.eof())
For getting every line in the file, you should use:
while(getline(inFile, cities[count].city)) {
// ...
This works and is recommended over using the .eof() method.
You can also use this in your if-statement:
if (!getline(inFile, str))
break;
As an aside, you can read this site:
Why is “while ( !feof (file) )” always wrong? - StackOverflow post
It gives insight into why using the .eof() is not the preferred method to use in a while loop to check whether the end-of-file has been reached.
Use getline as loop condition. You can also replace the second read with a getline too and use a stringstream to parse it.
#include <sstream>
// ...
while(getline(inFile, cities[count].city)) {
if (cities[count].city.empty()) break;
// read next line with high and low values
string str;
if (!getline(inFile, str)) break; // error in file format
stringstream ss(str);
char comma;
ss >> cities[count].high >> comma >> cities[count].low; // parse it
}
I want to know whether I'm using the right form to get my command in a line and then by some ifs get the info each command needs. This is a part of my code; actually, the first part of my main function:
string line;
stringstream ss;
while (!cin.eof())
{
getline(cin, line);
//i dont know if next line should be used
ss << line;
if (line.size() == 0)
continue;
ss >> command;
if (command == "put")
{
string your_file_ad, destin_ad;
ss >> your_file_ad >> destin_ad;
//baraye history ezafe shod
give_file(your_file_ad, p_online)->index_plus(command);
I tried to run your code with two additional couts in your if, to see what happens when for example user enters put a b.
So, this is my code:
string line;
stringstream ss;
while (true)
{
getline(cin, line);
//i dont know if next line should be used
ss << line;
if (line.size() == 0)
continue;
string command;
ss >> command;
if (command == "put")
{
string your_file_ad, destin_ad;
ss >> your_file_ad >> destin_ad;
cout << "input #1 is " << your_file_ad << endl;
cout << "input #2 is " << destin_ad << endl;
}
}
When I run this code, then if I write put a b in the console, I'll see this result, which is correct:
input #1 is a
input #2 is b
But it seems that this only works for the first command. after that commands couldn't process correctly.
So, I read the code again, and found out that the problem is, you are initializing your stringstream outside of the while.
I'm not sure why exactly it doesn't work (maybe already reached EOF and can't continue reading anymore?), but if you move stringstream ss; inside the while, it'll work correctly:
string line;
while (true)
{
stringstream ss;
getline(cin, line);
//i dont know if next line should be used
ss << line;
if (line.size() == 0)
continue;
string command;
ss >> command;
if (command == "put")
{
string your_file_ad, destin_ad;
ss >> your_file_ad >> destin_ad;
cout << "input #1 is " << your_file_ad << endl;
cout << "input #2 is " << destin_ad << endl;
}
}
Update: read #LightnessRacesinOrbit comment below about the issue with the first code.
Those are the parts of the code I have:
ifstream inFile;
inFile.open("Product1.wrl");
...
if (!inFile.is_open()){
cout << "Could not open file to read" << endl;
return 0;
}
else
while(!inFile.eof()){
getline(inFile, line);
cout << line << endl; //this statement only to chech the info stored in "line" string
if (line.find("PointSet"))
inFile >> Point1;
}
The output shows me the same string over and over again. So this means that the cursor inside the file does not proceed and getline reads the same line.
What might be the problem of this odd behavior?
If this is relevant:
The file does open as a .txt file and contains the exact information I need.
Okay I figured the problem:
Even after first eteration the return value of line.find("PointSet")is: 429467295... while my line string contains only one letter "S". Why?
Change
while(!inFile.eof()){
getline(inFile, line);
to
while( getline(inFile, line) ) {
I don't know why people get bitten by eof() quite so often, but they do.
Mixing getline with >> is problematic, because the >> will leave a '\n' in the stream, so the next getline will come back empty. Change that to use getline as well.
if (line.find("PointSet")) isn't what you want either. find returns the position in the string, or std::string::npos if it wasn't found.
Also, you can change
ifstream inFile;
inFile.open("Product1.wrl");
to
ifstream inFile ("Product1.wrl");
Here's a version showing the reads:
class Point
{
public:
int i, j;
};
template <typename CharT>
std::basic_istream<CharT>& operator>>
(std::basic_istream<CharT>& is, Point& p)
{
is >> p.i >> p.j;
return is;
}
int main()
{
Point point1;
std::string line;
while(std::getline(std::cin, line))
{
std::cout << line << '\n'; //this statement only to chech the info stored in "line" string
if (line.find("PointSet") != std::string::npos)
{
std::string pointString;
if (std::getline(std::cin, pointString))
{
std::istringstream iss(pointString);
iss >> point1;
std::cout << "Got point " << point1.i << ", " << point1.j << '\n';
}
else
{
std::cout << "Uhoh, forget to provide a line with a PointSet!\n";
}
}
}
}
I have a .txt file with names and grades such as "emiltytaco 56". After the last name, there are 3 blank lines which should not be inserted into my trie and heap. However the code is Aborted and dumped when hitting the blank lines. This is the insert function
while(myfile.good())
{
getline(myfile, line);
name = line.substr(0,line.find("\t"));
stringstream convert((line.substr(line.find("\t")+1)));
convert >> grade;
if(name.at(0) > 96 && name.at(0) < 123)
{
insert(name, grade);
cout << name << " " << grade << endl;
}
}
myfile.close();
should the .close be part of an "else" statement with the if? a friend of mine has this exact thing but his does not abort.
First point, change your loop to something like:
while (getline(myfile, line)) {
// ...
}
Second, it's probably a lot simpler to feed the whole line to the stringstream, and read both pieces from there:
stringstream convert(line);
std::getline(convert, name, '\t');
convert >> grade;
Third, if you want to check for lower-case letters, you're much better off with islower than comparisons to magic numbers like 96 and 123. I wouldn't do the check that way though. If you want to check for a blank line, it would be better to do that directly, with line.empty() immediately after you read it. Using that, you end up with something like:
while (getline(myfile, line))
if (!line.empty()) {
std::istringstream convert(line);
std::getline(convert(line, name);
convert >> grade;
insert(name, grade);
std::cout << name << " " << grade << "\n";
}
There is one more step beyond that though: since the name and grade are (apparently) related, I'd probably define a class for them, and write an extractor to get an object of that type from a stream:
class whatever {
std::string name;
int grade;
friend std::istream &operator>>(std::istream &is, whatever &w) {
std::getline(is, w.name, '\t');
is >> w.grade;
is.ignore(4096, '\n');
return is;
}
};
With that in place, we can read the data from the file quite a bit more simply:
whatever w;
while (myfile >> w) {
insert(w);
std::cout << w.name << " " << w.grade << "\n";
}
Note that in this case, we don't have to check for the blank lines explicitly at all -- we just check whether we could successfully read and convert a whatever from the stream, which will fail for a blank line.