Perl Weekly Challenge 287.
My solutions (task 1 and task 2 ) to the The Weekly Challenge - 287.
Task 1: Strong Password
Submitted by: Mohammad Sajid Anwar
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
Example 1
Input: $str = "a"
Output: 5
Example 2
Input: $str = "aB2"
Output: 3
Example 3
Input: $str = "PaaSW0rd"
Output: 0
Example 4
Input: $str = "Paaasw0rd"
Output: 1
Example 5
Input: $str = "aaaaa"
Output: 3
A seemingly simple solution would be:
- If the password is missing characters of one class (lowercase, uppercase, digit) add one character.
- If it has a consecutive sequence of 3 equal characters, replace the last one.
- If the resulting string has
n<6characters, and a character6-ntimes.
If there is a sequence of 3 equal characters and a character class is
missing I can replace one of the repeated characters by one of the
missing class and solve both problems with just one step. On the other
hand, if there is a sequence of 3 equal characters and the string is
too short, I could break the sequence by adding, instead of replacing,
a character, solving two problems. The added character could also be
of a missing class, if any, thereby solving three problems. However, for
example, for a string of 5 consecutive characters a replacement would
solve the problem of repeated characters, while adding a new character
still leave a problematic
string of 3 consecutive characters. For example, …aaaaa… could become
…aabaa… after a replacement, or …aabaaa… after an addition,
producing a longer string if needed, but still with three consecutive
a’s. In both cases, b could be replaced by B or 0 if
characters of another class are required. This could lead to a complicated
solution for passwords with a large minimum length. Nevertheless, as
the required length is small, 6, it turns
out that the only problematic case would be that of a string made up
of exactly 3 equal
characters, for which addition is better than substitution. For
example, aaa can be converted to aaAa and then to aaAa0 and to
aaAa0a, whixh is better than converting aaa to aAa, aAa0,
aAa0a and aAa0aa. As I don’t have to actually convert the
password, just to count the required number of steps, this leads to a
code that fits into a two liner.
Examples:
perl -MList::Util=max -E '
for(@ARGV){$s=/^(.)\1\1$/;$c=(!/[a-z]/)+(!/[A-Z]/)+(!/[0-9]/);my $t;++$t while/(.)\1\1/g;
$c=max($c-$t,0);$h=max(6-(length)-$c,0);say "$_ -> ", $s?3:$t+$h+$c;}
' a aB2 PaaSW0rd Paaasw0rd aaaaa aaa
Results:
a -> 5
aB2 -> 3
PaaSW0rd -> 0
Paaasw0rd -> 1
aaaaa -> 2
aaa -> 3
The next to last solution differs from that in the statement of the problem, but I can verify it is correct by constructing the strong password step by step:
| step | password | action |
|---|---|---|
| 0 | aaaaa | |
| 1 | aaAaa | replace by upper case |
| 2 | aaAaa0 | add digit |
Similarly, I construct the solution for the last example:
| step | password | action |
|---|---|---|
| 0 | aaa | |
| 1 | aaAa | add upper case char |
| 2 | aaAa0 | add digit |
| 3 | aaAa0x | add any other char |
The full code is:
1 # Perl weekly challenge 287
2 # Task 1: Strong Password
3 #
4 # See https://wlmb.github.io/2024/09/16/PWC287/#task-1-strong-password
5 use v5.36;
6 use List::Util qw(max);
7 die <<~"FIN" unless @ARGV;
8 Usage: $0 P1 P2...
9 to find the minimum number of steps required to convert
10 the passwords Pi into strong passwords
11 FIN
12 for(@ARGV){
13 my $single_triad=/^(.)\1\1$/;
14 my $missing_classes=(!/[a-z]/)+(!/[A-Z]/)+(!/[0-9]/);
15 my $triads=0;
16 ++$triads while /(.)\1\1/g;
17 my $missing_classes=max($missing_classes-$triads, 0);
18 my $missing_chars=max(6-(length)-$missing_classes, 0);
19 my $steps=$single_triad?3:$triads+$missing_chars+$missing_classes;
20 say "$_ -> $steps";
21 }
Examples:
./ch-1.pl a aB2 PaaSW0rd Paaasw0rd aaaaa aaa
Results:
a -> 5
aB2 -> 3
PaaSW0rd -> 0
Paaasw0rd -> 1
aaaaa -> 2
aaa -> 3
Task 2: Valid Number
Submitted by: Mohammad Sajid Anwar
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.
Example 1
Input: $str = "1"
Output: true
Example 2
Input: $str = "a"
Output: false
Example 3
Input: $str = "."
Output: false
Example 4
Input: $str = "1.2e4.2"
Output: false
Example 5
Input: $str = "-1."
Output: true
Example 6
Input: $str = "+1E-8"
Output: true
Example 7
Input: $str = ".44"
Output: true
I build and use a regular expression to capture the rules above. I explain the expression in the full code below. The code fits a one-liner.
Examples:
perl -E '
say "$_ -> ", 0+/^(\+|-)?(\d+|\d+\.\d*|\d*\.\d+)((e|E)(\+|-)?\d+)?$/?"true":"false" for @ARGV;
' 1 a . 1.2e4.2 -1. +1E-8 .44
Results:
1 -> true
a -> false
. -> false
1.2e4.2 -> false
-1. -> true
+1E-8 -> true
.44 -> true
In the full code I use an extended regular expression to make it more intelligible.
1 # Perl weekly challenge 287
2 # Task 2: Valid Number
3 #
4 # See https://wlmb.github.io/2024/09/16/PWC287/#task-2-valid-number
5 use v5.36;
6 die <<~"FIN" unless @ARGV;
7 Usage: $0 S1 S2...
8 to find which strings Si represent valid numbers.
9 FIN
10 my $re = qr/ # regular expression
11 ^ # start of string
12 (\+|-)? # optional sign
13 (\d+ # integer
14 | \d+\.\d* # or integer part and optional decimal part
15 | \d*\.\d+ # or optional integer part and decimal part
16 )
17 ( # exponent
18 (e|E) # letter e or E
19 (\+|-)? # optional sign
20 \d+ # integer exponent
21 )? # is optional
22 $ # end of string
23 /x; # extended syntax
24 say "$_ -> ", /$re/?"true":"false" for (@ARGV);
Examples:
./ch-2.pl 0 1 a . 1.2e4.2 -1. +1E-8 .44
Results:
0 -> true
1 -> true
a -> false
. -> false
1.2e4.2 -> false
-1. -> true
+1E-8 -> true
.44 -> true
/;