C++ cin whitespace question - c++

Programming novice here. I'm trying to allow a user to enter their name, firstName middleName lastName on one line in the console (ex. "John Jane Doe"). I want to make the middleName optional. So if the user enters "John Doe" it only saves the first and last name strings. If the user enters "John Jane Doe" it will save all three.
I was going to use this:
cin >> firstName >> middleName >> lastName;
then I realized that if the user chooses to omit their middle name and enters "John Doe" the console will just wait for the user to enter a third string... I know I could accomplish this with one large string and breaking it up into two or three, but isn't there a simpler way to do it with three strings like above?
I feel like I'm missing something simple here...
Thanks in advance.

Use getline and then parse using a stringstream.
#include <sstream>
string line;
getline( cin, line );
istringstream parse( line );
string first, middle, last;
parse >> first >> middle >> last;
if ( last.empty() ) swap( middle, last );

Related

Read elements from a txt file that are separeted by a character

I'am working on a program where there are first names, last names and a numbers on a file and i need to read that information into my program. My actual problem is that there is people who doesnt have a second name or second last name. To solve the issue I started trying to read from a file until a specific character is found, For example:
Robert, Ford Black,208 //Where Robert is the first name, and Ford Black are his two last names
George Richard, Bradford,508 //Where George Richard are both his first names, and Bradford is his only last
name
I am saving this information in three separeted string, one that will store first and second name, first last and second last name and the third one for the numbers.
I'm trying to only use native libraries from c++.
I've been reading that getline(a,b,c) and IStringStream can actually solve my problem but I don't know how to correctly implement it
It's just a matter of using std::getline with a delimiter character to read out of the string stream. See a simplified example (no error checking) below:
for (std::string line; std::getline(std::cin, line); )
{
std::string firstName, lastName;
std::istringstream iss(line);
std::getline(iss, firstName, ','); // A comma delimits end-of-input
iss >> std::ws; // Skip over any whitespace characters
std::getline(iss, lastName); // Read remaining line
std::cout << "First Name: " << firstName << std::endl;
std::cout << "Last Name: " << lastName << std::endl;
}
Note the line iss >> std::ws; using std::ws from <iomanip> is there to eat up extra whitespace characters (which appear after your comma, in your example).
I'm assuming the C++ line comments in the input are only an annotation for this question, and not part of the actual input.
#include<bits/stdc++.h>
using namespace std;
int main()
{
ifstream myfile("files.txt");
string fullname;
while(getline(myfile,fullname,'/')) break; //here im reading till the first / is acquired and the entire string is stored in "fullname"
string firstname,lastname;
size_t pos=fullname.find(',');
firstname=fullname.substr(0,pos); //store the firstname
lastname=fullname.substr(pos+1);// storee the lastname
cout<<firstname<<" "<<lastname;
}
As the question posed was to read names im assuming before the digit if there were a " / " you can read upto the first occurance of /. this will give you the fullname. Then using the substr on the fullname and find the occurance of a comma if at all it exists. All the characters to the left of position of comma will form your first name and the rest on the right of the position of comma will form the lastname.

How to make c++ using cin optional?

I want to allow user to input three strings from the keyboard. For example, firstname, lastname and middle name. The middle name is optional.
The code sample below:
cout << "Enter your name, first name then middle name and last name (Ex: Abby Scuito S): ";
char lastName[21], firstName[21], middleName[21];
cin >> lastName >> firstName >> middleName;
The problem is that it always ask for middle name input when the third block is missing which is correct based on how cin works. The problem is that I cannot figure out how to make it optional.
For example,
Input 1: Abby Scuito A => Output: Abby Scuito A
Input 2: Abby Scuito => Output: Abby Scuito
Read the data into a single string and separate them by space.
You may have to do some filtering, but you'll get the idea.

The cin.ignore removing first character the second time function is being called

Can anyone tell me what is wrong with this? Without cin.ignore, the getline would not work, and after the first time when I call the function again, the first character is removed. So far I have tried using stringstream instead of getline, cin.sync(), cin.clear(), but nothing seems to work. Also the reason why I am using getline, is because some streets have spaces between them, so simply using cin would not work in this case
std::cout << "Enter Street Name 1: " ;
std::cin.ignore(1,EOF);
std::getline(std::cin,s1);
std::cout << "Enter Street Name 2: " ;
std::getline(std::cin,s2);
std::cout<<"Your first street was: "<<s1<<" Your second street was: "<<s2 <<". Please look at the map to find the intersection of " << s1 << " and " << s2 <<std::endl;
Output
Enter Street Name 1: Bloor
Enter Street Name 2: Yonge
Your first street was: Bloor Your second street was: Yonge. Please look at the map to find the intersection of Bloor and Yonge
Enter Street Name 1: Bloor
Enter Street Name 2: Yonge
Your first street was: loor Your second street was: Yonge. Please look at the map to find the intersection of loor and Yonge
Enter Street Name 1: Bloor
Enter Street Name 2: Uong
Your first street was: loor Your second street was: Uong. Please look at the map to find the intersection of loor and Uong
Without cin.ignore, the getline would not work,
That is true only if there is some code before that that leaves a newline character in the input stream.
and after the first time when I call the function again, the first character is removed.
That makes sense. cin.ignore() reads and discards one character.
I am not able to suggest something that will fix your problem without a Minimal, Complete, and Verifiable Example.
because you use cin.ignore() without parameters which means ignore the next char in the buffer that's why the first character is removed. To use cin.ignore()
cin.ignore( int nCount = 1, int delim = EOF );
Parameters
nCount - The maximum number of characters to extract.
delim - The delimiter character (defaults to EOF).
example
std::cin.ignore(256,' '); // ignore until space

Reading data from a text file with different variable types in C/C++

I'm building a simple family tree using classes, where each person has an ID and can have one or more relationships, and each relationship also has an ID. I'm trying to import this file in order to be able to use the class methods to import a tree:
9
Charless
0
F
2 5
Dianaaaa
0
M
1
William
1
M
6
Harry
1
M
-1
...
For some context, the text file shows the number of people in the tree, name, son of relationship number X, gender, and ID of the person this person has a relationship with. If the person doesn't have any relationships, "-1" is shown. I'm incrementing the IDs automatically as I add a person or a relationship through the class methods. To import the file, I'm doing something like this:
ifstream f2;
f2.open("databasev2.txt");
string name; char gender;
int personrelationshipid; int sonofrelationshipid;
int numberOfPeople;
vector<int>relationships;
f2 >> numberOfPeople;
if (f2.is_open())
{
while (f2 >> name >> sonofrelationshipid >> gender )
{
while (f2 >> personrelationshipid)
{
relationships.push_back(personrelationshipid);
f2.ignore(0, ' ');
}
//...do something with the variables
My current problem is that the loop is stopping after the first iteration. I'm not sure if it's considering that the second name "Dianaaa" is no longer a string... Right now, it is reading "9", "Charless", "0", "F", "2" and "5", and inserting them into the vector, and then it stops. If I only have one relationship, this doesn't happen (i.e. if I remove the 5)
Moreover, I would like to add names with spaces between them - to do this, I think I just need to create a string and use f2.getline(name,string), then clear the buffer and remove the newline character so I don't have trouble reading the next line, am I right?
I can't use boost/JSON to serialize the information - I have to do this manually, so I would appreciate some help in "reinventing the wheel". However, I can edit the file as I want, adding some delimiters.
Thanks in advance
You need to call f2.clear() every time a loop quits, because you use the stream as a boolean operand. Therefore when the loop quits, there are error flags which cause subsequent stream operations to fail.
You need to clear the state of the file stream, with std::basic_ios::clear() function, inside the outer loop:
while (f2 >> name >> sonofrelationshipid >> gender)
{
while (f2 >> personrelationshipid)
{
relationships.push_back(personrelationshipid);
}
if (!f2.eof())
f2.clear();

Read file with multiple spaces word by word c++

I want to read .txt file word by word and save words to strings. The problem is that the .txt file contains multiple spaces between each word, so I need to ignore spaces.
Here is the example of my .txt file:
John Snow 15
Marco Polo 44
Arya Stark 19
As you see, each line is another person, so I need to check each line individualy.
I guess the code must look something like this:
ifstream file("input.txt");
string line;
while(getline(file, line))
{
stringstream linestream(line);
string name;
string surname;
string years;
getline(linestream, name, '/* until first not-space character */');
getline(linestream, surname, '/* until first not-space character */');
getline(linestream, years, '/* until first not-space character */');
cout<<name<<" "<<surname<<" "<<years<<endl;
}
Expected result must be:
John Snow 15
Marco Polo 44
Arya Stark 19
You can just use operator>> of istream, it takes care of multiple whitespace for you:
ifstream file("input.txt");
string line;
while(!file.eof())
{
string name;
string surname;
string years;
file >> name >> surname >> years;
cout<<name<<" "<<surname<<" "<<years<<endl;
}