How to only accept character on c++ - c++

In my program, when the user is prompted for an employee's name, the system prompts him to re-enter his name if he enters a number or only a space. How do I put a requirement decision in parentheses in a while loop, here's my code.
std::string NAME;
std::cout << "Please enter the name: " << std::endl;
std::cin >> NAME;
while (NAME.length() == 0) {
std::cout << "Your input is not correct. Please re-enter your name" << std::endl;
std::cin >> NAME;
}
I'm only going to restrict the input to not being empty, but I don't know how to get the user to only allow characters to enter.
Thank you all.

You can use std::all_of on the string defined in algorithm header file. It should be used with appropriate predicate (isalpha for your case defined in cctype header file). Try this:
#include <iostream>
#include <algorithm>
#include <cctype>
int main()
{
std::string NAME;
std::cout << "Please enter the name: " << std::endl;
while (std::getline(std::cin, NAME)) {
if (NAME.length() == 0)
{
std::cout << "Your input is not correct. Please re-enter your name" << std::endl;
}
// This will check if the NAME contains only characters.
else if (std::all_of(NAME.begin(), NAME.end(), isalpha))
{
break;
}
else {
std::cout << "Only characters are allowed:" << std::endl;
}
}
}

Every character has an ASCII code. Use an if condition to check if an input character falls between the ASCII codes for the English alphabets. ASCII Table. You can convert a character to its ASCII code by simply type-casting it as an integer.
Example: For a character array "ARR", having data: "apple"; doing the following will give you "97".
std::cout << (int)ARR[0] << std::endl;

Related

How Do I read and Output the Contents of a File and the Number of Words it Contains?

I am attempting to write a program for homework which reads the contents of a notepad file and displays the contents and the number of words int he file. My code currently outputs nothing when I enter the name of the names of files I am using to test the program, and the input validation while loop I inserted does not function either.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
//Declare needed variables
string fileName, contents;
int wordCount = 0;
ifstream inData;
//Display program info
cout << "*** A SIMPLE FILE PROCESSING PROGRAM ***" << endl;
//Prompt user input
cout << "Enter a filename or type quit to exit: ";
cin >> fileName;
inData.open(fileName.c_str());
//Inform the user when their input is invalid and ask them to input another
file name
while (!inData)
{
inData.clear();
inData.ignore(200, '\n');
cout << "File not found. Please type a correct file name." << endl;
cin >> fileName;
inData.open(fileName.c_str());
}
inData >> contents;
//Read and output the contents of the selected file
while (inData)
{
cout << fileName << " data\n";
cout << "***********************" << endl;
inData >> contents;
wordCount++;
cout << contents << endl;
inData >> contents;
}
//Display the number of words in the file
cout << "***********************" << endl;
cout << fileName << " has " << wordCount << " words." << endl;
inData.close();
return 0;
}
The code compiles in its current state [but does not produce the desired outcome.
I will show you one of the many possible solutions.
But I would not recomend, to check the validity of a filename in a loop. You will give the user no chance to escape. Hence, I propose to open the file, and, if that does not work, show an error message and quit.
Then, what sounds easy in the beginning like, count the words, is not really that easy. What is a word? Characters only, or characters mixed with digits or even an underscore in it like for C++ variable names? Needs to be defined.
Additionally you may have separators like commas or one and more other white spaces. So a line like "Hello,,,,World" cannot be so easily counted. If you try to read the 2 words, then you will see a surprise.
std::string s1{};
std::string s2{};
std::istringstream iss("Hello,,,,World");
iss >> s1 >> s2;
Will read everything in s1!
The solution is that we define clearly what a word is. And this we will do with a std::regex. In the below example we use characters, digits and _
Then we use the regex_iterator to find all occurences of the regex (the word) in the line. We substract the end from the beginning with std::distance, which will give us the count of the words.
Then we give an output to the user in whatever format.
It may seem complicated. But it is precise. And rather flexible. Try to anaylze line by line and you will understand it.
Please see:
#include <iostream>
#include <string>
#include <regex>
#include <fstream>
#include <iomanip>
int main()
{
// Get a filename from the user
std::cout << "Enter a filename:\n";
std::string filename{}; std::cin >> filename;
// Try to open and read the file
std::ifstream fileStream(filename);
if (fileStream) {
// We will count all words
size_t numberOfWordsOverall{ 0 };
// We will also count the lines in the file
size_t lineCounter{ 1 };
// Define, what a word is. In this case: Characters, Digits and _
std::regex regexForWord("[\\w\\d_]+");
// Read all lines in file
std::string line{};
while (std::getline(fileStream, line)) {
// Count the numbers of words in one line
const size_t numberOfWordsInLine = std::distance(
std::sregex_token_iterator(line.begin(), line.end(), regexForWord, 1),
std::sregex_token_iterator()
);
// Update the overall word counter
numberOfWordsOverall += numberOfWordsInLine;
// Show result to user
std::cout << "# " << std::left << std::setw(2) << lineCounter++ << " (Words in line: "<< std::setw(2) << numberOfWordsInLine <<
" Words overall: " << std::setw(4) << numberOfWordsOverall << ") Line content --> " << line << '\n';
}
}
else {
std::cerr << "Could not open file '" << filename << "'\n";
}
return 0;
}
Hope this helps . . .

C++ c2664 error "cannot convert argument 1 from std::string to _Elem *"

I've been stuck on this homework assignment all week. Just when I get the program to finally run, I realize that by using just cin >> breed, if my input has a space it ruins the code (as my program requires gathering 3 separate variables, first an int, then a string, and last a bool). Because this is the second variable, it messes up my code using phrases that have a white character. When I try changing it to cin.get or cin.getline, this is the error message I get:
c2664 error "cannot convert argument 1 from std::string to _Elem *"
Below is the code in question (the middle line is giving the error). Any help would be greatly appreciated!
#include <iostream>
#include <string>
using namespace std;
int main()
{
int birthyear;
string breed;
bool vaccines;
cout << "Please enter value for dog's birth year: ";
cin >> birthyear;
cout << "What is the breed of the dog: ";
cin.getline(breed, 100);
cin.ignore();
cout << "Has the dog been vaccinated (1 = Yes/ 0 = No): ";
cin >> vaccines;
}
First up, you need to be aware that there are two getline things in C++, one in the I/O area and one in the top-level standard namespace.
cin.getline(breed, 100) is the one in the I/O area (specifically istream::getline() and it knows nothing about strings, preferring to work on character arrays. You should probably avoid that one.
The one that does know about strings is std::getline() and that's generally the preferred one if you don't want to go back to the bad old days of C-legacy "strings".
In addition, you need to be careful in C++ when you mix the type-specific input (like <<) and line-specific input (like getline) operations. It's important to know where the file pointer is before and after each operation.
For example, cin << someInt will leave the file pointer immediately after the integer it reads in. That means, if your next operation is getline(), it's likely to find everything on the line after that integer (at the bare minimum, this will be the newline character that you entered to get the integer processed), not the next line where you're going to be typing in your string.
A simple fix for your case is to ignore everything up to and including the newline before you attempt to get the next line. That can be done with ignore():
#include <iostream>
#include <string>
#include <limits>
using namespace std;
int main() {
int birthyear; string breed; bool vaccines;
cout << "Please enter value for dog's birth year: ";
cin >> birthyear;
cout << "What is the breed of the dog: ";
cin.ignore(numeric_limits<std::streamsize>::max(), '\n');
getline(cin, breed);
cout << "Has the dog been vaccinated (1 = Yes/ 0 = No): ";
cin >> vaccines;
// Output what you got.
cout << birthyear << " '" << breed << "' " << vaccines << '\n';
}
You could also opt for ensuring all input is line-based (converting those lines to the correct type once they're entered) since that's likely to ease your task of ensuring the pointers are in the right place, and that errors in input (like entering xyzzy for an integer) can be better handled.
Something like this should be a good start:
#include <iostream>
#include <string>
#include <limits>
#include <set>
#include <cstdlib>
using namespace std;
// Get string, always valid. Optionally strip leading and
// trailing white-space.
bool getResp(const string &prompt, string &val, bool strip = false) {
cout << prompt;
getline(cin, val);
if (strip) {
val.erase(0, val.find_first_not_of(" \t"));
val.erase(val.find_last_not_of(" \t") + 1);
}
return true;
}
// Get unsigned, must ONLY have digits (other than
// leading or trailing space).
bool getResp(const string &prompt, unsigned long &val) {
string str;
if (! getResp(prompt, str, true)) return false;
for (const char &ch: str)
if (! isdigit(ch)) return false;
val = strtoul(str.c_str(), nullptr, 10);
return true;
}
// Get truth value (ignoring leading/trailing space),
// and allow multiple languages.
bool getResp(const string &prompt, bool &val) {
string str;
if (! getResp(prompt, str, true)) return false;
const set<string> yes = {"yes", "y", "1", "si"};
const set<string> no = {"no", "n", "0", "nyet"};
if (yes.find(str) != yes.end()) {
val = true;
return true;
}
if (no.find(str) != no.end()) {
val = false;
return true;
}
return false;
}
// Test driver for your situation.
int main() {
unsigned long birthYear;
std::string dogBreed;
bool isVaccinated;
if (! getResp("What year was the dog born? ", birthYear)) {
std::cout << "** ERROR, invalid value\n";
return 1;
}
if (! getResp("What is the breed of the dog? ", dogBreed, true)) {
std::cout << "** ERROR, invalid value\n";
return 1;
}
if (! getResp("Has the dog been vaccinated? ", isVaccinated)) {
std::cout << "** ERROR, invalid value\n";
return 1;
}
std::cout
<< birthYear
<< " '" << dogBreed << "' "
<< (isVaccinated ? "yes" : "no") << '\n';
}

Error in output in c++ program

The purpose of the program is to read a phrase from a file into a vector and convert the phrase into Pig Latin. When the translated phrase is outputted in Pig Latin, an additional "ay" is added after the phrase (which is not supposed to happen). Can anyone spot why this is happening? It is important that I fix this because it affects the total letters and total characters of the Pig Latin phrase that I need to output. Also, I'm not asking anyone to write any code for me, but any tips on how to make my code less redundant. A portion of my grade for programs is efficiency, which I usually lose points on.
Here's the code:
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <stdio.h>
#include <ctype.h>
using namespace std;
int main()
{
ifstream in;
string word, fileName;
vector <string> phrase;
int length = 0, index = 0;
int totalWords = -1, totalLetters = -3, totalChars;
cout << "PIG LATIN PROGRAM" << endl;
cout << "Which file are you accessing? : ";
cin >> fileName;
fileName += ".txt";
in.open(fileName);
if (in.fail()) cout << "\nFile not found!" << endl;
while(getline(in, word)) phrase.push_back(word);
cout << "Original Phrase: " << phrase[0] << endl;
istringstream iss(phrase[0]);
cout << "Pig Latin phrase: ";
do {
string OGword;
string PLword;
for (int i=0; i < phrase.size(); i++){
iss >> OGword;
totalWords++;
}
if (OGword[0]=='a' || OGword[0]=='A' || OGword[0]=='e' || OGword[0]=='E' || OGword[0]=='i' || OGword[0]=='I' || OGword[0]=='o' || OGword[0]=='O' || OGword[0]=='u' || OGword[0]=='U'){
cout << OGword << "way" << " ";
totalLetters += (OGword.size() + 3);
}
else {
PLword = OGword.substr(index);
length = PLword.length();
PLword.insert(length, "ay");
PLword.insert(length, 1, OGword[index]);
PLword.erase(0, 1);
if (isupper(OGword[0])){
transform(PLword.begin(), PLword.end(), PLword.begin(), ::tolower);
(toupper(PLword[1]));
char upper;
upper = toupper(PLword[0]);
PLword.erase(0, 1);
cout << upper;
}
cout << PLword << " ";
totalLetters += PLword.size();
}
} while (iss);
totalChars = totalLetters + 1;
cout << "\n\nTotal words: " << totalWords << endl;
cout << "Total Letters: " << totalLetters << endl;
cout << "Total Characters: "<< totalChars << endl;
}
Problem
The core loop of the program looks like this (in pseudocode):
istringstream iss; // Contains line of text.
do {
string OGword;
get_OGword_and_count_totalWords(iss, OGword);
print_pig_latin_of_word(OGword);
} while (iss);
The loop runs as long as iss has not experienced an error. And in particular, iss does not experience an error until an extraction operation fails. So things happen in the loop like this:
OGword contains the last legitimate word on the line.
Print the last word.
The while clause is tested. iss is still good at this point because no error has occurred, even if iss is at the end of string.
Attempt to extract a word into OGword. This fails, and leaves OGword empty ("").
Print the Pig Latin version of "", which is "ay".
The while clause is tested. iss is in an error state, and the loop ends.
Fix
One possible fix out of many is to test iss for an error immediately after extracting a word.
std::istringstream iss; // Contains line of text
std::string OGword;
while (iss >> OGword) {
increment_word_total();
print_pig_latin_of_word(OGword);
}
In this version, the operation iss >> OGword returns iss, which is converted to bool. If there was an error during the immediately preceeding extraction, the loop ends without printing anything.
Other Advice
I think the best way to improve readability is to break the code up into smaller functions. For instance, take the if / else block that formats and prints the Pig Latin, and actually put it in a function:
int print_pig_latin_of_word_and_return_total_letters(string_view word);
Then, the code in that function can be further subdivided:
bool starts_with_vowel(std::string_view word);
int print_vowel_word_and_count_letters(std::string_view word);
int print_consonant_word_and_count_letters(std::string_view word);
int print_pig_latin_of_word_and_count_letters(std::string_view word) {
if (starts_with_vowel(word)) {
return print_vowel_word_and_count_letters(word);
} else {
return print_consonant_word_and_count_letters(word);
}
}
Odds and Ends
I would drop using namespace std and write all of the std library names as std::string, etc. This makes it clear which things are from the standard library.
The program has interesting behavior on input files that contain more than one line. There is a for loop that loops over phrase.size() which is number of input lines. This causes words to be skipped and totalWords to be incorrect.
This statement doesn't do anything, because the result of toupper is ignored:
(toupper(PLword[1]));

Password function and arrays

I'm writing a simple password program, but the else if statement always applies, even if the password is put in correctly. This works fine if I use a single char instead of an array, and change "hotdog" to 'h', and I think it might have something to do with unseen characters, like a space or return. I was sure cin.ignore() took care of return/enter.
Sorry, I'm fairly new to programming.
#include <iostream>
int main()
{
std::cout << "What is the password?\n" << std::endl;
char password[20] = "NULL";
std::cin >> password;
std::cin.ignore();
std::cout << password << " is your entry?\n";
if (password == "hotdog")
{
std::cout << "Correct!";
}
else if (password != "hotdog")
{
std::cout << "Incorrect!";
}
else
{
}
std::cin.get();
}
Firstly, change char password[20] to string password. This prevents a buffer overflow if they type in more than 20, and it enables you to use == for string comparison.
The code std::cin.ignore() ignores a single character. You want to actually ignore the entire remainder of the line. There is no way to ignore "everything else typed so far" because there may have been characters typed which are still buffered. In practice, it works well to treat input as a series of lines.
The most accurate way to ignore the rest of the line is to ignore all characters up to and including '\n', which appears in the input stream at the end of the line (by definition).
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
which may require #include <limits>. Another way is to read a string and discard it:
std::string t;
std::getline( std::cin, t );
NB. Check your understand of if...else . Once you have if ( condition ), then the next else will already get everything that was not in that condition. It's pointless to actually write else if ( !condition ); and your final else { block can never be entered, because the previous two conditions were exhaustive.
The problem is with how you are using the if-else statement. Try this code out:
#include <iostream>
int main()
{
std::cout << "What is the password?\n" << std::endl;
char password[20] = "NULL";
std::cin >> password;
std::cin.ignore();
std::cout << password << " is your entry?\n";
if (stricmp("hotdog", password) == 0)
{
std::cout << "Correct!";
}
else
{
std::cout << "Incorrect!";
}
std::cin.get();
}
When I take your code and compile it, even the term hotdog does not work properly, I obtain the following:
What is the password?
hotdog
hotdog is your entry?
Incorrect!
As suggested above, a string is a better method and works as intended based on your requirements. Here is sample replacement code that works as intended (with this code spaces are allowed, with the other answers, spaces are not, it all depends what is intended):
#include <iostream>
#include <string>
using namespace std;
int main (int argc, char ** argv)
{
cout << "What is the password?\n" << endl;
string password = "NULL";
getline(cin, password);
cout << password.c_str() << " is your entry?\n";
if (password == "hotdog")
{
cout << "Correct!";
}
else if (password != "hotdog")
{
cout << "Incorrect!";
}
else
{
// Added from original; however, this should never occur
cout << "Else?";
}
system("pause");
return 0;
}
Output of Replacement Code
What is the password?
hotdog
hotdog is your entry?
Correct!
You had to use strcmp() function to compare strings properly in c++,so I added the cstring library:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
int main(){
string password;
cin >> password;
cout << password << " is your entry?\n";
char hd [7] = "hotdog";
if (strcmp(password.c_str(),hd) == 0){
cout << "Correct!\n";
}
else if (strcmp(password.c_str(),hd) != 0){
cout << "Incorrect!\n";
}
else{
cin.get();
}
}

Validate the length of a char * taken from std::cin

I have a pointer called char * panimal_name. This pointer should only be able to take in 20 characters and if the user enters more, it must ask the user to re-enter.
I've tried counting the characters in the stream and also using strlen(), however I'm still having problems.
cout << "Enter Animal Name: ";
cin.ignore();
cin.getline(panimal_name, 20);
Any help would be appreciated.
EDIT: Well I only want it to take at most 20 characters from the user. If that 20 is exceeded it should then ask the user to re-enter valid input. However in this setup, it now messes up the stream for my next inputs. The reason I'm using this, rather than a std::string, is that I'm learning pointers at the moment.
P.S. I know a string would probably be better in this situation for ease of use.
According to MSDN:
If the function extracts no elements or _Count - 1 elements, it calls
setstate(failbit)...
You could check for that failbit to see if the user entered more data than the buffer allows?
You can use c++ methods..
std::string somestring;
std::cout << "Enter Animal Name: ";
std::cin >> somestring;
printf("someString = %s, and its length is %lu", somestring.c_str(), strlen(somestring.c_str()));
you can also use more c++ methods
std::string somestring;
std::cout << "Enter Animal Name: ";
std::cin >> somestring;
std::cout << "animal is: "<< somestring << "and is of length: " << somestring.length();
I guess you could do something with cin to a stringstream to get around the way that cin exctract works.
Consider the following program:
#include <iostream>
#include <string>
#include <limits>
// The easy way
std::string f1() {
std::string result;
do {
std::cout << "Enter Animal Name: ";
std::getline(std::cin, result);
} while(result.size() == 0 || result.size() > 20);
return result;
}
// The hard way
void f2(char *panimal_name) {
while(1) {
std::cout << "Enter Animal Name: ";
std::cin.getline(panimal_name, 20);
// getline can fail it is reaches EOF. Not much to do now but give up
if(std::cin.eof())
return;
// If getline succeeds, then we can return
if(std::cin)
return;
// Otherwise, getline found too many chars before '\n'. Try again,
// but we have to clear the errors first.
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n' );
}
}
int main () {
std::cout << "The easy way\n";
std::cout << f1() << "\n\n";
std::cout << "The hard way\n";
char animal_name[20];
f2(animal_name);
std::cout << animal_name << "\n";
}
Use a larger buffer for user input and check for the last element of your buffer.