# 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<6`

characters, and a character`6-n`

times.

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
```

/;