Perl Weekly Challenge 185: MAC Address and Mask Code

These are some answers to the Week 185 of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Task 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

MAC Address in Raku

This is done in a hurry, less than 45 minutes before the deadline. There might be a better or simpler way to solve this task, but using a couple of regexes is so simple that I don’t see any reason to try something else.

for "1ac2.34f0.b1c2", "abc1.20f1.345a" -> $test {
    $_ = $test;
    s:g/\./:/;
    s:g/(\w\w)(\w\w)/$0:$1/;
    .say;
}

This script displays the following output:

$ raku ./mac-address.raku
1a:c2:34:f0:b1:c2
ab:c1:20:f1:34:5a

MAC Address in Perl

Also using two regexes in Perl:

use strict;
use warnings;
use feature qw/say/;

for my $test ("1ac2.34f0.b1c2", "abc1.20f1.345a") {
    $_ = $test;
    s/\./:/g;
    s/(\w\w)(\w\w)/$1:$2/g;
    say;
}

This script displays the following output:

$ perl ./mac-address.pl
1a:c2:34:f0:b1:c2
ab:c1:20:f1:34:5a

Task 2: Mask Code

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')

Mask Code in Raku

The idea is to iterate over the input string and use a regex substitution to replace alphanumeric characters with “x” four times.

I started this task trying to use only one counter ($count), but quickly found that there are a number of edge cases where it would not work properly. So we need to manage separately the number of successful matches ($count) and the place where to start the next search ($/.to, i.e. the atom next to the last successful match).

Note that I initially used the \w character class, but then changed it to <[\w] - [_]> to remove the “_” (underscore) from it.

constant MAX = 4;
my @tests = <ab-cde-123  123.abc.420  3abc-0010.xy  1234567.a
             a-1234-bc  a.b.c.d.e.f  12__34567.a>;
for @tests -> $test {
    my $count = 0;
    my $result = $test;
    my $pos = 0;
    while $count < MAX {
        $count++ if $result ~~ s:c($pos)/<[\w] - [_]>/x/;
        $pos = $/.to;
    }
    say "$test\t => $result";
}

This script displays the following output:

$ raku ./mask-code.raku
ab-cde-123       => xx-xxe-123
123.abc.420      => xxx.xbc.420
3abc-0010.xy     => xxxx-0010.xy
1234567.a        => xxxx567.a
a-1234-bc        => x-xxx4-bc
a.b.c.d.e.f      => x.x.x.x.e.f
12__34567.a      => xx__xx567.a

Mask Code in Perl

I used a different strategy in Perl: the input string is split into an array of characters in order to test each character individually.

use strict;
use warnings;
use feature qw/say/;
use constant MAX => 4;

my @tests = qw<ab-cde-123  123.abc.420  3abc-0010.xy  1234567.a
               a-1234-bc  a.b.c.d.e.f  12__34567.a>;
for my $test (@tests) {
    my $result = "";
    my $count = 0;
    for my $char (split //, $test) {
        if ($count < MAX and $char =~ /[A-Za-z0-9]/) {
            $char = 'x';
            $count++;
        }
        $result .= $char;
    }
    say "$test\t => $result";
}

Note that this program would not work the same way as the Raku program above for strings containing non-ASCII alphanumeric characters, but I don’t really care, since we have not been given any indication on how to manage non-ASCII Unicode characters. It would not be difficult to obtain the same behavior as the Raku program with something like this:

    if ($count < MAX and $char =~ /[A-Za-z0-9]/ and $char ne '_') {

This script displays the following output:

$ perl ./mask-code.pl
ab-cde-123       => xx-xxe-123
123.abc.420      => xxx.xbc.420
3abc-0010.xy     => xxxx-0010.xy
1234567.a        => xxxx567.a
a-1234-bc        => x-xxx4-bc
a.b.c.d.e.f      => x.x.x.x.e.f
12__34567.a      => xx__xx567.a

Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on October 16, 2022. And, please, also spread the word about the Perl Weekly Challenge if you can.

Leave a comment

About laurent_r

user-pic I am the author of the "Think Perl 6" book (O'Reilly, 2017) and I blog about the Perl 5 and Raku programming languages.