How to make c++ using cin optional? - c++

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.

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.

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

C++ Reading tab-delimited input and skipping blank fields

I am making a program that will take a long string of tab-delimited metadata pasted into the console by the user and split them into their correct variables. I have completed the code to split the line up by tab, but there are empty fields that should be skipped in order to put the correct metadata into the correct string variable, which I can't get to work.
Here is the code that I have so far:
string dummy;
string FAImport;
cin.ignore(1000, '\n');
cout << "\nPlease copy and paste the information from the finding aid and press Enter: ";
getline(cin, FAImport);
cout << FAImport;
stringstream ss(FAImport);
auto temp = ctype<char>::classic_table();
vector<ctype<char>::mask> bar(temp, temp + ctype<char>::table_size);
bar[' '] ^= ctype_base::space;
ss.imbue(locale(cin.getloc(), new ctype<char>(bar.data())));
ss >> coTitle >> altTitle >> description >> dateSpan >> edition >> publisher >>
physicalDescription >> scale >> extentField >> medium >> dimensions >> arrangement >>
degree >> contributing >> names >> topics >> geoPlaceNames >> genre >> occupations >>
functions >> subject >> langIN >> audience >> condition >> generalNotes >> collection >>
linkToFindingAid >> source >> SIRSI >> callNumber;
checkFAImport(); //shows the values of each variable
cout << "\n\nDone";
With this code, I get this output after inputing the metadata:
coTitle = William Gates photograph with Emiliano Zapata
altTitle = 1915
description = 1915
datespan = Electronic version
edition = 1 photograph : sepia ; 11 x 13 cm
publisher = L. Tom Perry Special Collections, Harold B. Lee Library, Brigham Young University
physicalDescription = Photographs
scale = William Gates papers
extentField = http://findingaid.lib.byu.edu/viewItem/MSS%20279/Series%2011/Subseries%205/Item%20979/box%20128/folder%2012
medium = William Gates photograph with Emiliano Zapata; MSS 279; William Gates papers; L. Tom Perry Special Collections; 20th Century Western & Mormon Manuscripts; 1130 Harold B. Lee Library; Brigham Young University; Provo, Utah 84602; http://sc.lib.byu.edu/
dimensions = MSS 279 Series 11 Subseries 5 Item 979 box 128 folder 12
arrangement =
degree =
contributing =
names =
topics =
geoPlaceNames =
genre =
occupations =
functions =
subject =
langIN =
audience =
condition =
generalNotes =
collection =
linkToFindingAid =
source =
SIRSI =
callNumber =
In this example, fields like altTitle and description should be blank and skipped. Any help would be much appreciated.
You've solved the issue with spaces in the fields in an elegant manner. Unfortunately, operator>> will skip consecutive tabs, as if they were one single separator. So, good bye the empty fields ?
One easy way to do it is to use getline() to read individual string fields:
getline (ss, coTitle, '\t');
getline (ss, altTitle, '\t');
getline (ss, description, '\t');
...
Another way is

C++ cin whitespace question

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