Simple casting conversion on C++ - 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;

Related

Sorting function with output to a separate file

I need to sort the input text document and write it into another test document. so that lines with an even number of words delete every second word, and lines with an odd number of words remain unchanged. The sorting should be performed as a function, the first pointer to the input of the string and the second pointer to the output.
I did the input and output, tried to do a sorting to begin with without a function, but nothing worked. can you tell me what I did not do the rule?
Example:
Input.txt
I do not like to go to school or study
I like to play games
Output.txt
I not to to or
I like to play games
string in, out;
cin >> in;
cin >> out;
ifstream input(in);
string str;
ofstream output(out);
string st;
while (getline(input, str))
{
do
{
int i = count(str.cbegin(), str.cend(), ' ');
if (i % 2 == 0)
st.append(str);
else
st.append(" ");
i++;
}
while (input);
output << st << endl;
}
The std::stringstream will be your friend.
Read about it here and especially for the useful std::istringstream here.
What can we do with this thing? We can put a string into it and then use the extraction operator >> like with any other stream.
So, counting words will become very simple. We read a line from the file as a std::string and then put it into a std::istringstream, Then we extract dummy words and increase a counter until the reading fails. Then we have the number of words.
Example:
// We read one line. Count the number of words
// Put the string in a stringstream to easily extract words
std::istringstream iss(line);
// Counter for words
unsigned int wordCount{};
// Dummy word
std::string tempWord{};
// Do the counting
while (iss >> tempWord) ++wordCount;
The stream tries too read until it cannot read any more (the stream is empty) and then sets a failbit. The failure of any stream can be checked with its bool operator or the !-operator. The while loop expects a boolean. And the extraction operation iss >> tempWord will return a reference to the stream and then its bool operator will be called and used as condition.
OK, understood, we can now count words. Next step is to skip words.
This is similar simple. In case of even number of words in a string, we will read always 2 words in a loop and simply throw the second one away.
Like this
std::string usedWord{};
// Read 2 words, ignore the second
while (iss >> usedWord >> tempWord)
result += (usedWord + ' ');
There are of course many other possible ways to solve that, but maybe the below solution can give you an idea.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
int main() {
// First read the input filename
std::cout << "\nPlease enter the path for the input file:\n";
std::string inputFileName{};
std::getline(std::cin, inputFileName);
// next read the output filename
std::cout << "\nPlease enter the path for the output file:\n";
std::string outputFileName{};
std::getline(std::cin, outputFileName);
// Open now both files. If one file cannot be opened, then no need tocontinue
// Open input file and check, if it could be opened
std::ifstream inputFileStream(inputFileName);
if (inputFileStream) {
// Input file could be opened without error.
// Now open output file and check, if it could be opened
std::ofstream outputFileStream(outputFileName);
if (outputFileStream) {
// Now, both input and output file streams are open
// Read lines
std::string line{};
while (std::getline(inputFileStream, line)) {
// We read one line. Count the number of words
// Put the string in a stringstream to easily extract words
std::istringstream iss(line);
// Counter for words
unsigned int wordCount{};
// Dummy word
std::string tempWord{};
// Do the counting
while (iss >> tempWord) ++wordCount;
// if the number of words is even then
if ((wordCount % 2) == 0) {
// Rinitialize stringstream
iss.clear(), iss.str(line);
// Here we store the resulting sentence
std::string result{};
// Now extract the word that we will keep and the other one that we will throw away
std::string usedWord{};
// Read 2 words, ignore the second
while (iss >> usedWord >> tempWord)
result += (usedWord + ' ');
// Write result to output
outputFileStream << result << '\n';
}
else
outputFileStream << line << '\n';
}
}
else std::cerr << "\n*** Error: could not open output file '" << outputFileName << "'\n\n";
}
else std::cerr << "\n*** Error: could not open input file '" << inputFileName << "'\n\n";
}

Why does stringstream stop receiving strings? [C++]

I'm trying to implement a way of reading inputs from text files to load different sets of coordinates more easily, but I've come across a bug I don't understand, where my stringstream object will stop receiving strings once one of the lines is ill-formatted.
In my output, you can see that the string is still intact when it's printed out, and then it's put into the stringstream on the very next line, but after one ill-formatted string, the stringstream stops containing anything when I print it out.
What's going on here?
Output:
This is what the text file looks like:
Method code:
ifstream pathfile(p.string());
cout << "Path file opened successfully.\n\n";
string line;
stringstream ss;
int x, y;
char comma,direction;
//Iterate all lines in the file
while(getline(pathfile,line)){
//remove all spaces from line
line.erase(remove(line.begin(), line.end(), ' '), line.end());
//skip comments and blank lines
if(line.c_str()[0] == '#' || line.empty()) continue;
//parse remaining lines
ss.str(string()); //clear stringstream
cout <<"LINE: "<<line<<endl;
ss << line;
cout <<"SS: "<<ss.str()<<endl;
if(ss >> x >> comma >> y >> comma >> direction)
cout << "X: "<<x<<" Y: "<<y<<" D: "<<direction;
else{
cout << "Ill-formatted line: ";
}
printf(" | %s\n\n", line.c_str());
}
pathfile.close();
Since the stream enters an error state when it fails to read an integer, you will need to clear the error state. To do that:
ss.clear();
The much easier thing to do is just move the definition of the stringstream into the loop:
istringstream ss(line);
if(ss >> x >> comma >> y >> comma >> direction)
// ...

input data from a file when each is a different type and a comma delimiter

I need to read from file a series of information that is separated by commas
example
Orionis, 33000, 30000, 18, 5.9
Spica, 22000, 8300, 10.5, 5.1
i'm having a hard time figuring out the getline structure to make this work. The CS tutor, in the lab, says to use a getline for this but i can't seem to make it work (visual studio doesn't recognize getline in this function)
#include <iostream>
#include <fstream>
#include "star.h"
#include <string>
using namespace std;
char getChoice();
void processSelection(char choice);
void processA();
(skipping crap you don't need)
static char filePath[ENTRY_SZ];
void processA() {
ifstream openFile;
long temp, test;
double lum, mass, rad;
char name;
cout << "Please enter the full file path" << endl;
cin >> filePath;
openFile.open(filePath, ios::in);
if (openFile.good() != true) {
cout << "this file path was invalid";
}
while (openFile.good())
{
star *n = new star;
// getline(openFile, name, ',');
star(name);
getline(openFile, temp, ',');
n->setTemperature(temp);
getline(openFile, lum, ',');
n->setLuminosity(lum);
getline(openFile, mass, ',');
n->setMass(mass);
cin >> rad;
n->setRadius(rad);
}
}
From what i'm reading online (including older posts) and what my CS tutor says this should work so any help will be appreciated.
The suggestion to use std::getline() is likely implying that you'd first read a std::string and then deal with the content of this std::string, e.g., using std::istringstream.
I'd suggest not to use std::getline() and, of course, to also check inputs after they are read. To deal with the comma separator after non-std::string fields I'd use a custom manipulator:
std::istream& comma(std::istream& in) {
if ((in >> std::ws).peek() == ',') {
in.ignore();
}
else {
in.setstate(std::ios_base::failbit);
}
return in;
}
This manipulator skips leading whitespace (using the manipulator std::ws) and then simply checks if the next character is a comma. If so, the comma is extracted, otherwise the stream is set into failure mode and further attempts to read will fail until the failure state is dealt with (e.g., by using in.clear() and probably getting rid of any offending characters).
With this manipulator it is easy to read the respective values. Note, that when switching from formatted to unformatted input it is likely necessary that leading whitespace (e.g., in this case line breaks) need to be ignored. Also, the code below first attempts to read the values and uses them only when this attempt was successful: input shall always be checked after a read attempt was made, not before!
// ...
long temp;
double lum, mass, rad;
std::string name;
while (std::getline(in >> std::ws, name, ',')
>> temp >> comma
>> lum >> comma
>> mass >> comma
>> rad) {
// use the thus read values
}

Modify cin to also return the newlines

I know about getline() but it would be nice if cin could return \n when encountered.
Any way for achieving this (or similar)?
edit (example):
string s;
while(cin>>s){
if(s == "\n")
cout<<"newline! ";
else
cout<<s<<" ";
}
input file txt:
hola, em dic pere
caram, jo també .
the end result shoud be like:
hola, em dic pere newline! caram, jo també .
If you are reading individual lines, you know that there is a newline after each read line. Well, except for the last line in the file which doesn't have to be delimited by a newline character for the read to be successful but you can detect if there is newline by checking eof(): if std::getline() was successful but eof() is set, the last line didn't contain a newline. Obviously, this requires the use of the std::string version of std::getline():
for (std::string line; std::getline(in, line); )
{
std::cout << line << (in.eof()? "": "\n");
}
This should write the stream to std::cout as it was read.
The question asked for the data to be output but with newlines converted to say "newline!". You can achieve this with:
for (std::string line; std::getline(in, line); )
{
std::cout << line << (in.eof()? "": "newline! ");
}
If you don't care about the stream being split into line but actually just want to get the entire file (including all newlines), you can just read the stream into a std::string:
std::string file((std::istreambuf_iterator<char>(in)),
std::istreambuf_iterator<char>());
Note, however, that this exact approach is probably fairly slow (although I know that it can be made fast). If you know that the file doesn't contain a certain character, you can also use std::getline() to read the entire file into a std::string:
std::getline(in, file, 0);
The above code assumes that your file doesn't contain any null characters.
A modification of #Dietmar's answer should do the trick:
for (std::string line; std::getline(in, line); )
{
std::istringstream iss(line);
for (std::string word; iss >> word; ) { std::cout << word << " "; }
if (in.eof()) { std::cout << "newline! "; }
}
Just for the record, I ended up using this (I wanted to post it 11h ago)
string s0, s1;
while(getline(cin,s0)){
istringstream is(s0);
while(is>>s1){
cout<<s1<<" ";
}
cout<<"newline! ";
}

boost lexical_cast throws exception

I'm using boost libs for c++ and the function lexical_cast behaves really weird. If I do lexical_cast("0.07513994") it works fine, but if I use my variable which I need to convert, it throws the bad_lexical_cast exception. Here is the code:
string word;
istringstream iss(line);
do
{
string word;
iss >> word;
double x;
x = lexical_cast<double>(word);
cout << x << endl;
} while (iss);
What am I doing wrong here? I appreciate any help, thanks
Your problem is probably that the loop is processed one more time than you expect.
The last time through the loop, the read to word fails, setting the fail bit in iss, which is what while(iss) is checking. To fix it you need to do something like this.
string word;
istringstream iss(line);
do
{
string word;
iss >> word;
if(iss)
{
double x;
x = lexical_cast<double>(word);
cout << x << endl;
}
} while (iss);
Unlike functions such as atof() which stop parsing as soon as they see an invalid character, lexical_cast requires that every character in the input string be valid. i.e. any leading or trailing spaces will cause it to throw an exception.
You want to see what kind of input it is getting and trim it accordingly. You should also catch bad_lexical_cast just in case it does get input which is completely garbage.
One possible solution is to use boos.regex or boost.xpressive to extract a valid sub-string and pass the result to lexical_cast.
The problem is probably that you are sending an empty string when there is no data left.
You should change the loop you are using.
Use the while {} loop (not the 'do while' loop). This allows you to read from the stream and test it in a single easy to read statement. Note the result of iss >> word is the stream. When used in this boolean context it is tested to see if the state is good and its value converted into something that can be used by the while condition. Thus if the operator >> filed to work correctly then the loop is never entered.
istringstream iss(line);
string word;
while(iss >> word)
{
double x = lexical_cast<double>(word);
cout << x << endl;
}
But really you don't even need the lexical cast in this situation (unless you want to test for non numbers with an exception). The standard stream operator will convert the input into a double.
istringstream iss(line);
double word;
while(iss >> word)
{
cout << word << endl;
}
if (iss.fail())
{ /* Failure to convert input to a double */
}