Perl Weekly Challenge: Week 185

Challenge 1:

MAC Address

You are given MAC address in the form i.e. hhhh.hhhh.hhhh.

Write a script to convert the address in the form hh:hh:hh:hh:hh:hh.

Example 1
Input:  1ac2.34f0.b1c2
Output: 1a:c2:34:f0:b1:c2
Example 2
Input:  abc1.20f1.345a
Output: ab:c1:20:f1:34:5a

This can be done as a one-liner in Perl:

shift =~ /(..)(..)\.(..)(..)\.(..)(..)/; say join q{:}, @{^CAPTURE};

(Full code on Github.)

...and in Raku:

@*ARGS[0] ~~ /(..)(..)\.(..)(..)\.(..)(..)/; @$/.join(q{:}).say

(Full code on Github.)

Both solutions assume the input is being given as a command-line argument. We capture each two character group in the input not counting separators and then join the capture groups together using colons and print the result. The regexp could perhaps be made more concise but this gets the job done.

Challenge 2:

Split Array

You are given a list of codes in many random format.

Write a script to mask first four characters (a-z,0-9) and keep the rest as it is.

Example 1
Input: @list = ('ab-cde-123', '123.abc.420', '3abc-0010.xy')
Output: ('xx-xxe-123', 'xxx.xbc.420', 'xxxx-0010.xy')
Example 2
Input: @list = ('1234567.a', 'a-1234-bc', 'a.b.c.d.e.f')
Output: ('xxxx567.a', 'x-xxx4-bc', 'x.x.x.x.e.f')

This one's a one-liner in Raku too. The input is given as command-line arguments. for each one, an alphanumeric character is replaced by an x upto 4 times. This limit is enforced by the handy :nth parameter to .subst(). Finally the transformed input is printed.

@*ARGS.map({ $_.subst(/<[a..z0..9]>/, "x", :nth(1..4)); }).say;

(Full code on Github.)

Perl, alas, does not have an equivalent to :nth so more code will be required. To make things clearer I put the code that transforms strings into a function called appropriately called transform(). It is called like this:

say q{(} . (join q{, }, map transform($_), @ARGV) . q{)};

(There's a little extra code to make the output look more like that shown in the spec.)

On to transform()....

sub transform {
    my $transformed = shift;

Four times in a loop, we convert a alphanumeric character to NUL. But weren't we supposed to convert it to x? The problem is that x itself is in the class [a-z0-9] so you end up only converting the first alphanumeric character over and over again. Instead we first convert it into a character which is unlikely to ever appear in a string (such as NUL) ...

    for (1 .. 4) {
        $transformed =~ s/[a-z0-9]/\0/;
    }

...and only after we have made all the necessary conversions, we in one fell swoop, convert all the NULs to xs.

    $transformed =~ s/\0/x/g;

Before returning this transformed string, we take the opportunity to enclose it in single quotes as that is how the example output does it.

    return "'$transformed'";
}

(Full code on Github.)