DEV Community

Simon Green
Simon Green

Posted on

Good things

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.

Challenge, My solutions

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.

  1. 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.
  2. If the password is too short, I store the number of missing characters as the variable char_count.
  3. 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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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))
Enter fullscreen mode Exit fullscreen mode

I use a regular expression, and will return True or False depending on whether is matches. Here is a breakdown of the regular expression:

  1. ^ and $ ensures that it matches the whole string.
  2. [+-]? allows for an optional signed prefix.
  3. ([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).
  4. Finally, ([eE][+-]?[0-9]+)? will optionally allow for the letter e, 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
Enter fullscreen mode Exit fullscreen mode

Top comments (0)