Perl Weekly Challenge: Week 272

Challenge 1:

Defang IP Address

You are given a valid IPv4 address.

Write a script to return the defanged version of the given IP address.

A defanged IP address replaces every period “.” with “[.]".

Example 1
Input: $ip = "1.1.1.1"
Output: "1[.]1[.]1[.]1"
Example 2
Input: $ip = "255.101.1.0"
Output: "255[.]101[.]1[.]0"

A nice easy one. We simply use .subst() to replace any . in the first command-line argument with [.]. (The :g flag ensures all matches are replaced.)

say @*ARGS[0].subst(".", "[.]",:g)

(Full code on Github.)

The Perl version is actually shorter than Raku for once. shift() uses @ARGV (the command-line arguments) as an implicit argument. The first element is removed and stored in $_. This is used as an implicit argument by s// and say().

$_ = shift; s/\./[.]/g; say

(Full code on Github.)

Challenge 2:

String Score

You are given a string, $str.

Write a script to return the score of the given string.

The score of a string is defined as the sum of the absolute difference between the ASCII values of adjacent characters.

Example 1
Input: $str = "hello"
Output: 13

ASCII values of characters:
h = 104
e = 101
l = 108
l = 108
o = 111

Score => |104 - 101| + |101 - 108| + |108 - 108| + |108 - 111|
      => 3 + 7 + 0 + 3
      => 13
Example 2
Input: "perl"
Output: 30

ASCII values of characters:
p = 112
e = 101
r = 114
l = 108

Score => |112 - 101| + |101 - 114| + |114 - 108|
      => 11 + 13 + 6
      => 30
Example 3
Input: "raku"
Output: 37

ASCII values of characters:
r = 114
a = 97
k = 107
u = 117

Score => |114 - 97| + |97 - 107| + |107 - 117|
      => 17 + 10 + 10
      => 37

First we split up $str (which we get from the command-line) into individual characters and store them as the list @chars.

my @chars = $str.comb;

Another variable is declared for storing the string score.

my $score;

Now we want to go through the indices of the @chars two by two. This means we should actually stop the loop at the index before the last one. This can be specified by .skip(1). Now .keys() will give us all the indices except for the last one.

for @chars.skip(1).keys -> $i {

For each index ($i) and the one after it ($i + 1) we find the ASCII value of the @chars element at those indices with .ord(). (Actually it is the Unicode value but that is the same for ASCII characters.) They are substracted from one another and because we only care about the magnitude of the difference not the sign, the result is run through .abs() for the absolute value. This is added to $score.

    $score += (@chars[$i].ord - @chars[$i + 1].ord).abs;
}

After all the character pairs have been processed, we print out $score.

say $score;

(Full code on Github.)

The Perl version is mostly the same.

my @chars = split //, $str;
my $score;

Unfortunately although Perl has keys(), it doesn't have an equivalent to .skip() so another approach must be used. What I did was to use scalar() to get the length of @chars and subtracted 2 from it. This gives us the index to the element before the last one.

for my $i (0 .. scalar @chars - 2) {
    $score += abs(ord($chars[$i]) - ord($chars[$i + 1]));
}

say $score;

(Full code on Github.)