Weekly Challenge 287
Each week Mohammad S. Anwar sends out The Weekly Challenge, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. It's a great way for us all to practice some coding.
Task 1: Strong Password
Task
You are given a string, $str
.
Write a program to return the minimum number of steps required to make the given string very strong password. If it is already strong then return 0.
Criteria:
- It must have at least 6 characters.
- It must contains at least one lowercase letter, at least one upper case letter and at least one digit.
- It shouldn't contain 3 repeating characters in a row.
Following can be considered as one step:
- Insert one character
- Delete one character
- Replace one character with another
My solution
This is definitely the harder of the two tasks this week. My whiteboard got a good workout for this one!
It appears that there isn't a use case where deleting a character would be more beneficial than replacing a character, so I can remove that from the equation.
There appears to be three types of changes, which I have defined as follows.
- Where there are three or more consecutive characters, we need to replace the third one with a different character. This is stored as
cons_count
. If there are six or more consecutive characters, we need to replace the 3rd and 6th character. Nine or more requires three changes and so on. - If the password is too short, I store the number of missing characters as the variable
char_count
. - The variable
type_count
counts the missing types. I add one if it is missing lower case letters, one if it is missing a capital letter, and 1 if it is missing a digit.
However, changes in the type_count
list can be covered by one of the two other changes. For example if Abbbbb
is the supplied password, we can change it to Abb1bb
which covers both the type change and the consecutive character change. Likewise Abcde
to Abcde1
would cover both type change and short password change.
Therefore I return the maximum of cons_count + char_count
and type_count
.
def strong_password(password: str) -> int:
cons_count = 0
for c in re.findall(r'((.)\2{2,})', password):
# For every 3 consecutive characters, we need to replace one
cons_count += len(c[0]) // 3
char_count = max(0, 6 - len(password))
type_count = 0
if not re.search(r'[a-z]', password):
type_count += 1
if not re.search(r'[A-Z]', password):
type_count += 1
if not re.search(r'[0-9]', password):
type_count += 1
return max(cons_count + char_count, type_count)
I believe this is the correct logic. There may have been some edge case that I have not considered.
Examples
$ ./ch-1.py a
5
$ ./ch-1.py aB2
3
$ ./ch-1.py PaaSW0rd
0
$ ./ch-1.py Paaasw0rd
1
$ ./ch-1.py aaaaa
2
Task 2: Valid Number
Task
You are given a string, $str
.
Write a script to find if it is a valid number.
Conditions for a valid number:
- An integer number followed by an optional exponent.
- A decimal number followed by an optional exponent.
- An integer number is defined with an optional sign '-' or '+' followed by digits.
Decimal Number: A decimal number is defined with an optional sign '-' or '+' followed by one of the following definitions:
- Digits followed by a dot '.'.
- Digits followed by a dot '.' followed by digits.
- A dot '.' followed by digits.
Exponent: An exponent is defined with an exponent notation 'e' or 'E' followed by an integer number.
My solution
This is relatively straight forward. Here is my solution.
def valid_number(s: str) -> bool:
return bool(re.search(r'^[+-]?([0-9]+\.?[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?$', s))
I use a regular expression, and will return True
or False
depending on whether is matches. Here is a breakdown of the regular expression:
-
^
and$
ensures that it matches the whole string. -
[+-]?
allows for an optional signed prefix. -
([0-9]+\.?[0-9]*|\.[0-9]+)
will match one of a digit optionally followed by a dot and optionally more digits (left side of|
, or a dot followed by one more digits (right side). - Finally,
([eE][+-]?[0-9]+)?
will optionally allow for the lettere
, an optional signed character, and one or more digits.
I use [0-9]
instead of \d
because in Perl, the later will match digits in languages other than English. This is discussed in a blog post I bookmarked a long time ago. https://blogs.perl.org/users/ben_bullock/2017/05/d-does-not-validate-numbers.html
Examples
$ ./ch-2.py 1.
True
$ ./ch-2.py 1.
true
$ ./ch-2.py a
false
$ ./ch-2.py .
false
$ ./ch-2.py 1.2e4.2
false
$ ./ch-2.py -1.
true
$ ./ch-2.py +1E-8
true
$ ./ch-2.py .44
true
Top comments (0)