Input validation using character array in C++ - c++

I am creating a C++ program to validate book name using a function in c++. The function must return 1 if the input is valid and 0 if the input is invalid. Book name can only contain upper case, lower case characters, color(:), comma(,) and space (there should be no consecutive spaces, commas, and colons). And the maximum characters in a character array is 60.
I tried the following way but I am not getting the desired answer.
const int MAX_BOOK_NAME = 60;
bool isValidBookName(char bookName[MAX_BOOK_NAME])
{
int length = strlen(bookName);
if (length > 59)
{
return false;
}
for (int i = 0; i < 59; i++)
{
if (bookName[i] < 'A' || bookName[i] > 'Z' || bookName[i] < 'a' || bookName[i] > 'z' || bookName[i] != ' ' || bookName[i] != ':' || bookName[i] != ',')
{
return false;
}
}
return true;
}
int main()
{
char arr[60];
cout << "Please Enter Your Book Id : ";
cin.getline(arr, 60);
cout << "Your Entered Name is " << isValidBookName(arr) << endl;
}

bookName[i] < 'A' || bookName[i] > 'Z' || bookName[i] < 'a' || bookName[i] > 'z'
These checks match every character because for example (assuming ASCII or compatible encoding) all capital letters match the condition bookName[i] < 'a' and all smaller case letters match bookName[i] > 'Z'. Since these checks are used to match an invalid character, the check is wrong.
std::isalpha can simplify your program greatly, as pointed out in comments.

The logic of your character check is flawed.
The requirement in your question is that each character must be a letter, or a comma, or a colon, or ... etc. The reverse of that is not "not a letter or not a comma or not a colon or ... etc." The reverse is "not a letter and not a comma and not a colon and ... etc."

Related

Count number of valid password based on some given restrictions

I have to count how many valid passwords are possible based on some given restrictions. The restrictions are following:
Minimum 10 characters and Maximum 14 characters.
Characters can include small English letters ('a'-'z'), Capital letters ('A'-'Z'), digits ('0'-'9') and special characters ('!','#','#','$','%','^','&','*','(',')')
Valid passwords must contain at least one of small letter, capital letter, digit and special character each.
Passwords cannot contain own student ID. Students ID are of 7 digits. First two digits denote year (00, 01, ... , 99), next two digits denote department code (00, 01, ... 99), and last three digits denote roll inside a department (000 - 180). So a student ID can be like: 1210142, where 12 denotes he is from batch 12, 10 is department code, and 142 is roll number. A student with ID 1210142 cannot have a password like Ti#s1210142mE but can have password like Ti#s121014m2E.
A student can use another student's ID in his/her own password.
Given the restrictions how many valid passwords can be generated?
I wrote a simple C++ program to simulate it. But as it is just a naive implementation, it would require a whole lot of time (maybe greater than my lifetime) to spit out an answer. Is there any clever way to figuring out the answer using code, possibly using regex or something like that?
My effort so far:
#include <iostream>
#include <algorithm>
inline bool is_valid_password(const std::string &generated_password, const std::string &student_id){
bool small = false, captial = false, digit = false, special = false;
for(const char &c : generated_password){
if(c >= 'a' && c <= 'z') small = true;
else if(c >= 'A' && c <= 'Z') captial = true;
else if(c >= '0' && c <= '9') digit = true;
else if(c == '!' || c == '#' || c == '#' || c == '$' || c == '%' || c == '^' || c == '&' || c == '*' || c == '(' || c == ')') special = true;
}
if(small && captial && digit && special){
return generated_password.find(student_id) == std::string::npos;
}
return false;
}
char valid_character_set [] = {
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'0','1','2','3','4','5','6','7','8','9',
'!','#','#','$','%','^','&','*','(',')'
};
long long comb(int N, int K, const std::string &student_id)
{
std::string bitmask(K, 1); // K leading 1's
bitmask.resize(N, 0); // N-K trailing 0's
long long counter = 0;
// print integers and permute bitmask
do {
std::string generated_password = "";
for (int i = 0; i < N; ++i) // [0..N-1] integers
{
if (bitmask[i]){
generated_password += valid_character_set[i];
}
}
if(is_valid_password(generated_password, student_id)) {
//std::cout << "valid password found: " << generated_password << '\n';
counter++;
}
} while (std::prev_permutation(bitmask.begin(), bitmask.end()));
return counter;
}
int main(int argc, char const *argv[])
{
std::cout << "Enter your student id: ";
std::string student_id; std::cin >> student_id;
std::cout << "Your student id is: " << student_id << "\n";
// all possible 10 character passwords
std::cout << comb(72, 10, student_id) << '\n';
return 0;
}
I don't know if you are familiar with writing regex, but if not, you can learn and try out a lot on this website. In my opinion, regex is a very powerful concept and it is worth it to invest some time to learn it.
Anyway, when you are familiar with regex, there is a very useful standard library for regex in C++. Just include
#include<regex>
And then you can instantiated your own regex object:
std::regex r = regex("yourRegexPattern");
With that object, you can invoke some useful functions, like regex_match() (which could be the right one for your use case), regex_search() or regex_replace().
For more information, I have linked the official reference above, or you can just google "c++ regex"
Edit: fixed links

Program for getting amount of words that start with Vowels and Consenants is returning wrong answers

Im writing a program for class and so far i have the word counter working fine and the vowel part working fine but Consonants and non alpha digits return wrong answers by 1(in certain cases). i think the problem lies in the testing of the characters them selves but i cant seem to find a way around it.
using namespace std;
int main()
{
char ch;
int count = 0;
int vowel = 0;
int cons = 0;
int noalph = 0;
bool inword = 1;
bool space = 0;
while (cin.get(ch)) {
if (ch != ' ') {
inword = 1;
}
if (isspace(ch)) {
space = 1;
}
else if (space && inword) {
count++;
space = 0;
inword = 0;
if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u' ||
ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U' ||
ch == 'y' || ch == 'Y') {
vowel++;
}
if (ch != 'a' && ch != 'e' && ch != 'i' && ch != 'o' && ch != 'u' &&
ch != 'A' && ch != 'E' && ch != 'I' && ch != 'O' && ch != 'U' &&
ch != 'y' && ch != 'Y'
&& isalpha(ch)) {
cons++;
}
if (ispunct(ch) || isdigit(ch)) {
noalph++;
}
}
}
if (count > 0) {
count++;
}
//--------------------------------------------
cout << "Total Number of Words = " << count << endl;
cout << "Number of Words Beginning with a Vowel = " << vowel << endl;
cout << "Number of Words Beginning with a Consonant = " << cons << endl;
cout << "Number of Words Beginning with a Non-Alpha = " << noalph << endl;
return 0;
}
Example 1(
Input:--------------------------------------------------------------------
supercalifragilisticexpialidocious
A nonsense-word used esp. by children, now chiefly expressing excited
approbation: fantastic, fabulous.
Made popular by the Walt Disney film "Mary Poppins" in 1964. The
song containing the word was the subject of a copyright infringement
suit brought in 1965 against the makers of the film by Life Music
Co. and two song-writers: cf. quots. 1949, 1951. In view of earlier
oral uses of the word sworn to in affidavits and dissimilarity between
the songs the judge ruled against the plaintiffs.
Taken from the OED.
Output:--------------------------------------------------------------------
Total Number of Words = 86
Number of Words Beginning with a Vowel = 25
Number of Words Beginning with a Consonant = 55
Number of Words Beginning with a Non-Alpha = 5
Expected:------------------------------------------------------------------
Total Number of Words = 86
Number of Words Beginning with a Vowel = 25
Number of Words Beginning with a Consonant = 56
Number of Words Beginning with a Non-Alpha = 5
)
Example 2(
Input:--------------------------------------------------------------------
1996
bottle
12345
radar
a Toyota
Madam, I'm Adam
Was it a rat I saw?
Norma is as selfless as I am, Ron.
A man, a plan, a canal--Panama!
Tarzan raised Desi Arnaz' rat.
Hannah
Lewd did I live, & evil I did dwel.
Excerpts from "The Zen of Programming"
Mary said, "I like the STL."
Output:--------------------------------------------------------------------
Total Number of Words = 56
Number of Words Beginning with a Vowel = 20
Number of Words Beginning with a Consonant = 31
Number of Words Beginning with a Non-Alpha = 4
Expected:------------------------------------------------------------------
Total Number of Words = 56
Number of Words Beginning with a Vowel = 20
Number of Words Beginning with a Consonant = 31
Number of Words Beginning with a Non-Alpha = 5
)
As you can see it breaks at different points, maybe its something simple maybe it not, i would just like some help understanding what is going on, Thank You!
OK, you didn't followed advices in comments, so let do it explicitly.
You are skipping the first word.
Cause of the initialization in this line:
bool space = 0;
you should initialize it as true
bool space = true;
(yes, use true and false for boolean).
you should see that cause you added this lines
if (count > 0) {
count++;
}
to cover this problem. So, remove them.
You also skipped the #include <iostream> directive.

Counting the number of letters/digits

My goal is to write a C++ program that can read a text file and:
Count the average number of letters/sentence.
Count the total amount of digits.
The text file would be read with command "./a.out < textfile"
What I've tried so far is to have the program check each character at a time with "cin >> current". I have a while loop. If current hits a punctuation mark, it should increase linecount by 1. It should also be reading for alpha characters, but I'm not sure how to make it count those.
#include <iostream>
#include <iomanip>
#include <cmath>
#include <cctype>
using namespace std;
int main()
{
int letters; //Total number of letters per sentence
int digits; //Total number of digits
int sentencecount; //Number of sentences
float averageletters; //Average number of letters per sentence
int linecount ; //Count of lines
char current; //Current character
cin >> current;
digits = 0;
letters = 0;
while (cin)
{
if (current == '.' == '!' == '?')
linecount++;
//calcuate averages and other sentence data
//reset sentence data
if (isalpha(current))//repeat for digits
letters++;
cout << "line #" << letters << endl;
cin >> current;
}
return 0;
}
if (current == '.' == '!' == '?')
The line above doesn't do what it think you does. Suppose current is a exclamation point. Then this evaluates to:
if (false == '!' == '?') // The character is NOT a '.'
Then:
if (false == '?') // '!''s value is > 0, so the condition checks if true == false
And finally:
if (false) // For the same reasons as above
To fix your condition, use:
if (current == '.' || current == '!' || current == '?')
This uses the boolean OR operator to check if any of the conditions inside the statement are true, under which case to go inside the if statement. You can also add parentheses to the condition to increase readability.
if (current == '.' == '!' == '?')
probably won't evaluate they way you intend. You might want to read up on c++ operator precendence.
You could try-
if ((current == '.') || (current == '!') || (current == '?'))

C++ how to cout once instead of multiple times in a for loop

void f3(string x){
for (int i=0; i < x.length(); i++){
if ('A'<=x[i] && 'z'>=x[i]){
cout << "English Alphabet" << endl;
}
else {
cout << "NOT English Alphabet" << endl;
break;
}
}
}
how to get only one result (cout)? like "English Alphabet" instead of 4 times for "abcd".
examples:
gimme a string:
abcd
English Alphabet
English Alphabet
English
Alphabet
English Alphabet
or
gimme a string:
abc!
English Alphabet
English Alphabet
English
Alphabet
NOT English Alphabet
and if I input space the program does not work.
How could I fix it?
Thanks for the help!
I am not sure if I got what you want, and I do not know C++, but something that may help you is using a boolean to define whether or not the input has non-English characters in it. You would define it as true from the beginning, and as soon as you find a character that isn't an English character, you set it to false. When you step out of the for loop, you use an if to check if your input has only English characters. It would be something like this:
void f3(string x) {
bool isEnglish = true;
for (int i=0; i < x.length(); i++){
if ('A'>x[i] || 'z'<x[i]){
isEnglish = false;
break;
}
}
if (isEnglish) {
cout << "English Alphabet" << endl;
} else {
cout << "NOT English Alphabet" << endl;
}
}
If you input space the program should run OK, but it will always return "not english alphabet" for it. That's because the test you're making takes into consideration if the current character of the input is between characters A and z of the ASCII character space. See the image below:
See how space is character number 32, which is smaller than 'A', and therefore, will not enter your if block, and fall inside the else, thus returning 'NOT English alphabet'. Numbers, the # sign, the & sign and everything before 'A' and everything after 'z' will also fail the test. Also, brackets ('[' and ']') will pass as English alphabet input.
If you want to only include letters, your if should look like:
if (x[i] < 'A' || (x[i] > 'Z' && x[i] < 'a') || x[i] > 'z')
If you want to include spaces, add another &&:
if ((x[i] < 'A' || (x[i] > 'Z' && x[i] < 'a') || x[i] > 'z') && x[i] != ' ')
The same logic can be used to add any characters to your verification.
Good luck!
Since you've tagged this as C++, I'm going to assume you're prefer a solution written in real C++.
First, I'd look up std::isalpha. It's defined specifically to determine whether a character is alphabetic1.
Second, I'd look up std::all_of and std::any_of. They're defined to determine whether any/all of a collection fits a particular requirement.
Putting those together, you could do something like this:
if (!std::all_of(x.begin(), x.end(),
[](unsigned char c) { return std::isalpha(c); })
std::cout << "Not ";
std::cout << "English alphabet\n";
1. Note that the result of isalpha isn't necessarily based on the English alphabet. Rather, it's based on the the current locale, so with (for example) a French locale, it would say that not only was an "a" alphabetic, but also that "â" and "à' were alphabetic as well (which your test would not). Likewise, for a German locale it would say "ß" was alphabetic (and so on). The default locale is named "C"; for things like determining whether something is alphabetic, it follows the English alphabet.
Here two solutions:
With a bool variable:
void f3(string x)
{
bool notEnglish = false;
for (int i=0; i < x.length(); i++)
{
if ( ('A' > x[i] || 'z' < x[i]) && x[i] != ' ' )
{
notEnglish = true;
break;
}
}
if (notEnglish) std::cout << "NOT ENGLISH" << std::endl;
else std::cout << "ENGLISH" << std::endl;
}
Without a bool and with int as return value:
int f3(string x)
{
for (int i=0; i < x.length(); i++)
{
if ( ('A' > x[i] || 'z' < x[i]) && x[i] != ' ' )
{
std::cout << "NOT ENGLISH" << std::endl;
return -1;
}
}
std::cout << "ENGLISH" << std::endl;
return 1;
}
I prefer the second one since you have a feedback (the return value) of what is occured inside the function.
You can declare a local Boolean variable so as soon as non-English detected the loop breaks immediately setting the the variable to false.
The matter is trickier: Checking for non-English characters:
void f3(string x){
bool IsEng = true;
for(int i = 0; i < x.length(); i++){
if ( !( x[i] >= 'A' && x[i] <= 'z') ){
IsEng = false;
break;
}
}
if(IsEng)
cout << "English Alphabet" << endl;
else
cout << "Not English Alphabet" << endl;
}
This is very simple and logical way to execute a line of code once:
int x=1
if (x==1)
{
//your cout-code here;
x++;
}
x becomes 2, so next time it won't be executed

Converting to lowercase at end of statement?

Slight issue. (Not using toupper() and tolower() functions) I understand what converting to uppercase and lowercase using numerical values is but following my C++ book, why is the conversion at the end of this statement and not before?:
if (letter >= 'A') //test for 'A' or larger
if (letter <= 'Z') //test for 'Z' or smaller
{
cout << endl
<< "You entered a capital letter."
<< endl;
letter += 'a' - 'A'; //Convert to lowercase
return 0;
}
if (letter >= 'a') //test for 'a' or larger
{
if (letter <= 'z') //test for 'z' or smaller
{
cout << endl
<< "You entered a small letter."
<< endl;
return 0;
}
}
Why would it convert the uppercase to lowercase at this point of code execution since the second if statement deals with lowercase input?
The given snippet could be the body of the function:
int convert(char& letter)
{
if (letter >= 'A' && letter <= 'Z')
{
letter += 'a' - 'A';
return 0; // go out of this function...
}
else if (letter >= 'a' && letter <= 'z')
{
letter += 'A' - 'a';
return 0; // go out of this function...
}
return -1; // it wasn't a letter as we expected
}
Note, that there's a possible path that doesn't match none of these 2 situation. Let's say that letter is '?', since you're returning int value, there should be an indication that something is wrong (it's up to you how you deal with error handling).
Possible usage of your this function could look like this:
char letter = '!';
if (convert(letter) == 0)
// success ...
else
// error ...
If the question is really about leaving the scope of function, then this question could be helpful too:
How to break out of a function
Concrete example:
void convertLetterAndPrintResult(char& letter)
{
if (convert(letter) == 0)
std::cout << letter << std::endl;
else
std::cout << "ERROR: '" << letter << "' is not valid character!" << std::endl;
}
int main()
{
char letter = '!';
convertLetterAndPrintResult(letter);
letter = 'g';
convertLetterAndPrintResult(letter);
letter = 'L';
convertLetterAndPrintResult(letter);
}
Output:
ERROR: '!' is not valid character!
G
l
Because there's a return 0; statement in the first part. If the original character was uppercase, the control flow doesn't even reach the second nested if () { if () { } } part.
Why would it convert the uppercase to lowercase at this point of code
execution since the second if statement deals with lowercase input?
That is because
return 0
means that the function is finished. The lines
if (letter >= 'a') //test for 'a' or larger
{
if (letter <= 'z') //test for 'z' or smaller
{
cout << endl
<< "You entered a small letter."
<< endl;
return 0;
}
}
will not be executed if letter was originally an upper case letter. It would print out "You entered a capital letter.", then convert it to lower case, then exit.
why is the conversion at the end of this statement and not before?
It would make no difference if the conversion were before the cout statement.