How can I cin a char with multiple words? - c++

I tried looking on the internet but I've not seen an answer.
So I have to cin a char with multiple words, like "Cars have four wheels." And I need to take every word and cout him. I learned at school that you can do this:
char a[100][20];
cin.getline(a, 100);
But it doesn't work. What's the proper way to cin a char with multiple words separate by a space;

You can try using std::istringstream for parsing the words.
std::vector<std::string> word_database;
std::string text_line;
while (std::getline(std::cin, text_line))
{
std::string word;
std::istringstream text_stream(text_line);
while (text_stream >> word)
{
word_database.push_back(word);
}
}
In the above code, one line of text is input to the text_line variable.
An istringstream is created using the line of text. The "words" are extracted from the text stream using operator>>. The words are appended to the database.

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;

StringStream input with comma delimited string - know columns apriori

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);
}

How to find a string of 2 words in a file?

With the following code, I can find a string of 1 word (in this example I'm looking for "Word"):
ifstream file("file.txt");
string str;
while (file >> str){
if (str.find("Word") != string::npos){
////
}
}
But it doesn't work if I want to find, for example, "Computer screen", which is composed of two words.
Thanks
file >> str reads a parameter (in this case, a string) delimited with whitespace. If you want to read the whole line (or in any case, more than one word at once), you can use getline operator (reads the string which is delimited by newline by default).
ifstream file("file.txt");
string str;
while (std::getline (file,str)){
if (str.find("Computer screen") != string::npos){
////
}
}
If you know there are two words and what they are, all you need is this:
ifstream file("file.txt");
string str;
while (file >> str){
if (str.find("Computer") != string::npos){
file >> str;
if (str.find("screen") != string::npos) {
////
}
}
}
But more likely, you are asking to find a single string that might be two words, or three or more.
Then, can you count on the string being on a single line? In which case, #Ashalynd's solution will work. But if the string might be broken it will fail. You then need to handle that case.
If your file is "small" - i.e. can easily fit in memory, read in the whole thing, remove line breaks and search for the string.
If it is too large, read in lines as pairs.
Something like this:
std::ifstream file("file.txt");
std::string str[2];
int i = 0;
std::getline (file,str[i]);
++i;
while (std::getline (file,str[i]))
{
int next_i = (i+1)%2;
std::string pair = str[next_i] + " " + str[i];
if (pair.find("Computer screen") != std::string::npos)
{
////
}
i = next_i;
}
All this assumes that the possible white space between the words in the string is a single space or a newline. If there is a line break with more white-space of some kind (e.g. tabs, you need either to replace white-space in the search string with a regex for white-space, or implement a more complex state machine.
Also, consider whether you need to manage case, probably by converting all strings to lower case before the match.

Parsing File I/O

I writing a C++ program that needs to be able to read from a .txt file, and parse the input in order to be able to get commands and arguments from each line.
Say I have Animals.txt
A cat1 3
A dog1 4
A cat2 1
D cat1
I want to be able to take this file, and then create a set of if statements for the first letter, so that I can call a function in the main class that corresponds to the first letter, and pass the rest of the line in as arguments.
An exmaple of what i'm trying to do:
if(line[0].compare("A")==0){
add(line[1],line[2]);
}
if(line[0].compare("D")==0){
delete(line[1])
}
I've tried to use strtok and the stringstream classes, but either I dont know how to implement the for my needs or they do not work for my needs as values are being put in line[0] that are not at the beginning of the lines of the text file.
Any help would be much appreciated.
First you need std::ifstream to open the file. Then you need std::getline to extract lines from the file:
std::ifstream file("Animals.txt");
std::string line;
while (std::getline(file, line)) {
// ...
}
Then inside the while loop, stick the line in a std::stringstream and extract the values you need:
std::stringstream ss(line);
char letter;
ss >> letter;
// And so on...
For a char you can do simple == comparison in your if statements:
if (letter == 'A') {
// ...
}
If you extract the letter into a std::string, just make sure you compare against "A".
I'll let you plug it all together and figure out the rest.
Create a istringstream object to split each line:
std::istringstream line(my_line);
std::string line0;
std::string line1;
std::string line2;
line >> token;
if (line0 == "A") {
line >> line1 >> line2;
add(line1, line2);
} else if (line0 == "D") {
line >> line1;
remove(line1);
}

While reading a file (ifstream), is there any way to direct it to make a new line?

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.