I am writing a program for school that is supposed to check the strength of passwords and separate them into 3 parameters. I am having an issue identifying special characters in a strong to classify a strong character. any help is greatly appreciated.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string input;
bool complete = false;
bool hasUpper = false;
bool hasLower = false;
bool hasDigit = false;
bool specialChar = false;
int count;
char special = 'a';
do
{
cout << endl << "Enter a password to rate its strength. Enter q to quit." << endl;
cin >> input;
for(count =0; count < input.size(); count++)
{
if( islower(input[count]) )
hasLower = true;
if( isupper(input[count]) )
hasUpper = true;
if( isdigit(input[count]) )
hasDigit = true;
special = input.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 ");
if (special != 'a')
specialChar = true;
}
if (hasLower && hasUpper && hasDigit && specialChar && (count >= 8))
{
cout << "Strong" << endl;
}
else if((hasLower || hasUpper) && hasDigit && (count >= 6))
{
cout << "Moderate" << endl;
}
else
{
cout << "Weak" << endl;
}
if (input == "q") complete = true;
}while (!complete);
return 0;
}
size_t special;
if (special != string::npos)
specialChar = true;
find_first_not_of returns the index of the found character, or the special value string::npos if no character is found.
Because find_first_not_of returns an index not a character, you must declare special as size_t not char.
This is more a comment on your code structure, than a direct
answer to your immediate question. (If you correct the
structure, the problem will disappear, however.) At present,
you seem to be mixing two different solutions, in a very odd
way. In particular, you're calling input.find_first_not_of
each time through the loop, despite the fact that it checks all
of the characters. You should choose one solution, and use it
for all of the conditions.
If you want to loop, checking each characters:
for ( int count = 0; count != input.size(); ++ count ) {
unsigned char ch = input[count]; // To avoid undefined behavior
if ( islower( ch ) {
hasLower = true;
} else if ( isupper( ch ) ) {
hasUpper = true;
} else if ( isdigit( ch ) ) {
hasDigit = true;
} else {
hasSpecial = true;
}
}
Note that the use of if/else if means that you don't need
a test for special—special is anything that doesn't meet any
of the preceding tests. If you wanted a test, !isalnum( ch )
would serve the purpose just fine.
Alternatively, you can use standard functions for each:
hasLower = std::find_if(
input.begin(),
input.end(),
[]( unsigned char ch ) { return islower( ch ); } )
!= input.end();
hasUpper = std::find_if(
input.begin(),
input.end(),
[]( unsigned char ch ) { return isupper( ch ); } )
!= input.end();
hasDigit = std::find_if(
input.begin(),
input.end(),
[]( unsigned char ch ) { return isdigit( ch ); } )
!= input.end();
hasSpecial = std::find_if(
input.begin(),
input.end(),
[]( unsigned char ch ) { return !isalnum( ch ); } )
!= input.end();
The lambda functions in the above is only available in C++11.
If you do not have C++11, you would have to write a separate
functional object for each, which would make this solution far
heavier than the simple loop above. Unless, of course, you're
doing a lot of text processing, in which case, the functional
objects would go in your tool kit, to be reused many times.
Unless you have the functional objects ready and in your tool
kit, however, this seems more complex than the simple loop, even
with lambda. (On the other hand, it's more idiomatic. But
then, it's hard to imagine any experienced C++ programmer
without the functional objects in his toolkit.)
Related
I'm a beginner in c++ and I'm training on exercises.
I'm stuck on one part. I would like to insert the string "CH" in front of each vowel in a sentence.
I first tried using string::replace, but it was not the best idea.
I would like to use string::insert to do this.
However, I can't seem to use it properly in a loop to tell it that the [i] is the desired position
Do you have any advice for me?
string message = "you have a secret message to decrypt";
string newMessage = "";
string InsertMessage = "CH";
for (int i = 0; i < message.length(); i++) {
if (
message[i] == 'a' ||
message[i] == 'e' ||
message[i] == 'i' ||
message[i] == 'o' ||
message[i] == 'u' ||
message[i] == 'y')
{
//newMessage = message.replace(i, 1, InsertMessage);
newMessage = message.insert(i, InsertMessage);
}
}
cout << newMessage << endl;
return 0;
This statement
newMessage = message.insert(i, InsertMessage);
does not make a sense at least because it changes the original string message.
I can suggest the following approach shown in the demonstration program below.
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
int main()
{
std::string message = "you have a secret message to decrypt";
std::string newMessage;
std::string InsertMessage = "CH";
const char *vowels = "aeiouy";
auto n = std::count_if( std::begin( message ), std::end( message ),
[vowels]( const auto &c ) { return std::strchr( vowels, c ); } );
newMessage.resize( message.size() + n * InsertMessage.size() );
std::string::size_type pos = 0;
do
{
auto i = message.find_first_of( vowels, pos );
if (i == std::string::npos)
{
newMessage += message.substr( pos );
pos = i;
}
else
{
newMessage += message.substr( pos, i - pos );
newMessage += InsertMessage;
pos = i;
newMessage += message[pos++];
}
} while( pos != std::string::npos );
std::cout << newMessage << '\n';
}
The program output is
CHyCHoCHu hCHavCHe CHa sCHecrCHet mCHessCHagCHe tCHo dCHecrCHypt
Thanks for your answers, I'll work on it :)
So writing a palindrome with pointers and boolean. I have it working with a single word but then I began building it to work with a sentence. The problem is I am unsure how to keep the new modified sentence after making it lowercase and getting rid of the spaces for it to return whether it is or isn't a palindrome. It keeps returning the palindrome as false and when I went to check why I see that the program ignores the modification and kept the original string. I can't use "&" on the parameter as I tested it out. Any hints or takes on what I can do to keep the new modified string?
int main()
{
userInput();
return 0;
}
void userInput()
{
char str[90];
std::cout<<"Please enter a string to check if it is a palindrome: ";
std::cin.getline(str, 90);
modifyString(str);
}
void modifyString(char *string)
{
int count = 0;
for (int i=0; i<strlen(string); i++)
{
putchar(tolower(string[i]));
}
for (int i = 0; string[i]; i++)
{
if (string[i] != ' ')
{
string[count++] = string[i];
}
}
string[count] = '\0';
std::cout<<string<<std::endl;
results(string);
}
bool checkPalindrome(char *string)
{
char *begin;
char *end;
begin = string;
end = (string + strlen(string)-1);
while(begin != end)
{
if ((*begin) == (*end))
{
begin ++;
end--;
}
else
{
return false;
}
}
return true;
}
void results(char *string)
{
bool isItPalindrome;
isItPalindrome = checkPalindrome(string);
if( isItPalindrome == true)
{
std::cout<<"\nCongrats, the string is a palindrome!";
}
else
{
std::cout<<"\nThis string is not a palindrome.";
}
}
For starters this definition of main
int main()
{
userInput();
return 0;
}
does not make a sense. According to the function name main the function should perform the main task that is to output whether the entered sentence is a palindrome or not.
This for loop
for (int i=0; i<strlen(string); i++)
{
putchar(tolower(string[i]));
}
does nothing useful. It just outputs the string in the lower case.
This statement
end = (string + strlen(string)-1);
can invoke undefined behavior if an empty string was passed.
This while loop
while(begin != end)
{
if ((*begin) == (*end))
{
begin ++;
end--;
}
else
{
return false;
}
}
also can invoke undefined behavior for a string containing an even number ofo characters because after this if statement
if ((*begin) == (*end))
{
begin ++;
end--;
}
if the two adjacent characters are equal then begin after incrementing will be greater than end after its decrementing. And as a result the loop will continue its iteration.
In general the approach when the original string is changed is just a bad approach.
Your program has too many functions. It is enough to write one function that will determine whether the passed string is a palindrome or not.
Here is a demonstrative program.
#include <iostream>
#include <cstring>
#include <cctype>
bool checkPalindrome( const char *s )
{
const char *t = s + std::strlen( s );
do
{
while ( s != t && std::isspace( ( unsigned char )*s ) ) ++ s;
while ( s != t && std::isspace( ( unsigned char )*--t ) );
} while ( s != t &&
std::tolower( ( unsigned char )*s ) == tolower( ( unsigned char ) *t ) &&
++s != t );
return s == t;
}
int main()
{
const size_t N = 100;
char s[N] = "";
std::cout << "Please enter a string to check if it is a palindrome: ";
std::cin.getline( s, N );
std::cout << '\n';
if ( checkPalindrome( s ) )
{
std::cout << "Congrats, the string is a palindrome!\n";
}
else
{
std::cout << "This string is not a palindrome.\n";
}
return 0;
}
Its output might look like
Please enter a string to check if it is a palindrome: 1 23 456 6 54 321
Congrats, the string is a palindrome!
Okay, I solved it!
As one of the users on here brought up a point that my lowercase did not modify the string and only prints it out. I try my best to solve the problem and I think I found the solution and everything works perfectly fine. comment back to debug it if you like to see how it looks but what I did was create a for loop again for the lower case but made another pointer with it. here how it looks.
for (char *pt = string; *pt != '\0'; ++pt)
{
*pt = std::tolower(*pt);
++pt;
}
Now that definitely changes the string into a lower case and keeps it as a lower case.
so now the modified function looks like this and ready to take any sentence palindrome you give it. Example: A nUt fOr a jAr of tUNa. We make this all lowercase and take out space and boom palindrome and return true.
void modifyString(char *string)
{
int count = 0;
for (char *pt = string; *pt != '\0'; ++pt)
{
*pt = std::tolower(*pt);
++pt;
}
for (int i = 0; string[i]; i++)
{
if (string[i] != ' ')
{
string[count++] = string[i];
}
}
string[count] = '\0';
//take out the forward slash below to see how it looks after being modified
// std::cout<<std::endl<<string<<std::endl;
results(string);
}
So, the goal is to check to see if the C style string ends with a period or exclamation mark. However, for some reason, i keep getting false.
bool isItSentence(const char* s)
{
int x = strlen(s);
for (int c = 0; s[c] != '\0'; c++)
{
if (!isupper(s[0])) return false;
if (isupper(s[c]) && c > 0) return false;
if (s[x-1] != '.') return false;
if (s[x-1] != '!') return false;
}
return true;
}
int main()
{
std::string str = "Smelly.";
reverse(str.c_str());
std::cout << isItSentence(str.c_str()) << std::endl;
std::cout << strlen(str.c_str()) << std::endl;
system("pause");
Heres what I have so far. But when I add the last if statement to handle exclamation marks, it returns zero. Any suggestions?
First, note s[x-1] is a loop invariant, so you'd rather move it out of the for loop
if (s[x-1] != '.') return false;
if (s[x-1] != '!') return false;
this is always false (a char cannot be both a dot and an explanation mark).
the test should rather be
if (s[x-1] != '.' && s[x-1] != '!') return false;
I am trying to validate if string has numeric or not. I want to see if string has character or more that are not allowed such as not numeric and/or one character "."
my codes are
//this code is call function (is_number). sTempArray[3] is amount such as $00.00
if(!is_number(sTempArray[3]))
{
cout << "Your amount have letter(s) are not allowed!;
}
//the is_number is function and will run if anyone call this function.
bool MyThread::is_number(const string& data)
{
string::const_iterator it = data.begin();
while (it != data.end() && std::isdigit(*it))
{
++it;
}
return !data.empty() && it == data.end();
}
I want to validate the string is allowed. For example, string has a value, it is 500.00 and it will be allowed but it always be denied because period character is in the string. Another example, string has a value, it is 500.00a and it should be not allowed.
In the while loop of your is_number function you could add an if statement to check if the the current iteration is a digit or to check if it is a "." in it (and maybe add a boolean value to check wether there was only one "."?).
It would look something like this:
bool MyThread::is_number(const string& data)
{
string::const_iterator it = data.begin();
while (it != data.end())
{
if (std::isdigit(*it) || it == "."){
++it;
}
}
return !data.empty() && it == data.end();
}
You can add a boolean flags if dot and digit was already met and modify the loop:
bool MyThread::is_number(const string& data)
{
bool dot_met = false, digit_met = false;
for( string::const_iterator it = data.begin(); it != data.end(); ++it )
{
if( is_digit( *it ) ) {
digit_met = true;
continue;
}
if( *it == '.' ) {
if( !digit_met || dot_met ) return false;
dot_met = true;
continue;
}
return false;
}
return digit_met;
}
Function in this form will not accept number started with . (like .05 ) if you do want that, change is trivial. Alternatively you can use regual expressions library, with "\\d+\\.?\\d*" expression.
I wrote the below code to check whether a certin string exists in a text or no. The issue is that match() function always returns false even the pattern exists in the text.
int main(){
char *text="hello my name is plapla";
char *patt="my";
cout<<match(patt,text);
system("pause");
return 0;
}
bool match(char* patt,char* text){
int textLoc=0, pattLoc=0, textStart=0;
while(textLoc <= (int) strlen(text) && pattLoc <= (int)strlen(patt)){
if( *(patt+pattLoc) == *(text+textLoc) ){
textLoc= textLoc+1;
pattLoc= pattLoc+1;
}
else{
textStart=textStart+1;
textLoc=textStart;
pattLoc=0;
}
}
if(pattLoc > (int) strlen(patt))
return true;
else return false;
}
Try pattLoc < (int)strlen(patt) in your while loop.
Loop will stop when pattLoc == 2, so you avoid comparing the '\0' of "my" with the ' ' of "hello my name is pala", which set pattloc to 0 and return false.
Or better, use string substr.
The obvious solution is:
bool
match( std::string const& pattern, std::string const& text )
{
return std::search( text.begin(), text.end(),
pattern.begin(), pattern.end() )
!= text.end();
}
This is idiomatic C++, and the way I would expect any C++ programmer to
write it, at least in a professional environment.
If the goal is to learn how to write such a function, then of course,
the above isn't much of a solution. The solution then should be mroe
divide and conquer; there's much too much in match for you to put it
in one function. I'd recommend something like:
bool
startsWith( std::string::const_iterator begin,
std::string::const_iterator end,
std::string const& pattern )
{
return end - begin >= pattern.size()
&& std::equal( pattern.begin(), pattern.end(), begin );
}
bool
match( std::string const& pattern, std::string const& text )
{
std::string::const_iterator current = text.begin();
while ( current != text.end()
&& !startsWith( begin, text.end(), pattern ) ) {
++ current;
}
return current != text.end();
}
This can obviously be improved; for example, there's no point in
continuing in the while loop when the length of the remaining text is
less than the length of the pattern.
And if your professor insists on your using char const* (if he insists
on char*, then he's totally incompetent, and should be fired), this
can easily be rewritten to do so: just replace all calls to begin with
the pointer, and all calls to end with pointer + strlen(pointer).
I have solved the problem:
while(textLoc <= (int) strlen(text) && pattLoc <= (int)strlen(patt))
should be:
while(textLoc < (int) strlen(text) && pattLoc < (int)strlen(patt))
and
if(pattLoc > (int) strlen(patt))
to
if(pattLoc >= (int) strlen(patt))