This is my response to The Weekly Challenge #185.
MAC address
in the form i.e. hhhh.hhhh.hhhh
.
hh:hh:hh:hh:hh:hh
.
Input: 1ac2.34f0.b1c2
Output: 1a:c2:34:f0:b1:c2
Example 2:
Input: abc1.20f1.345a
Output: ab:c1:20:f1:34:5a
Let us do the reverse operation as well.
File: mac-address
#! /usr/bin/env raku
multi sub MAIN ($mac-dot
where /^ <[0..9a..f]> **4 . <[0..9a..f]> **4 . <[0..9a..f]> **4 $/) # [1]
{
say $mac-dot.split(".")>>.map({ $_.substr(0,2) ~ ":" ~ $_.substr(2,2) }).join(":");
# # 2a ############# # 2b ############################################ # 2c ####
}
multi sub MAIN ($mac-colon
where /^ <[0..9a..f]> **2 \: <[0..9a..f]> **2 \: <[0..9a..f]> **2
\: <[0..9a..f]> **2 \: <[0..9a..f]> **2 \: <[0..9a..f]> **2 $/) # [3]
{
say $mac-colon.split(":").rotor(2)>>.join.join(",");
# # 4a ################ # 4b ## # 4c ## # 4d ####
}
Multiple dispatch (with multi
and a when
clause on the single
argument), is used to decide which operation to perform.
[1] The first regex matches four (the **4
quantifier) hexadecimal digits
(lowercase letters only) (the <[0..9a..f]>
regex), followed by a period
(the literal .
), another four hexadecimal chadigits, a second period and
finally another four hexadecimal digits.
[2] Start with the string, and split it on the periods. This gives us a list of strings
(3 of them, each consisting of 4 digits) [2a]. Then we use map
on each
of those strings (with the >>.
) to include a colon in the middle [2b]. And
finally we join the strings (3 of them) with a colon between each one [2c].
[3] This version matches 6 instances of two hexadecimal digits digits, with a colon betwean each one. Note that we had to escape the colon.
[4] Start with a list of 6 strings, each consisting of two hexadecimal
digits [4a]. Use rotor(2)
to group two and two elements in sublists,
giving a list with three elemens. Each element is again a list with two elements [4b].
Then we use >>.join
to join the elements of the sublist into a string, thus
giving a list with three string elements [4c]. And finally we join those strings together
with a period between each one [4d].
See
docs.raku.org/routine/rotor for
more information about rotor
.
Running it:
$ ./mac-address 1ac2.34f0.b1c2
1a:c2:34:f0:b1:c2
$ ./mac-address 1a:c2:34:f0:b1:c2
1ac2.34f0.b1c2
$ ./mac-address abc1.20f1.345a
ab:c1:20:f1:34:5a
$ ./mac-address ab:c1:20:f1:34:5a
abc1.20f1.345a
Looking good.
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')
I have chosen to hard code the lists this time.
File: mask-code
#! /usr/bin/env raku
my regex a9 { <[0..9 a..z]> }; # [1]
my @list1 = ('ab-cde-123', '123.abc.420', '3abc-0010.xy');
my @list2 = ('1234567.a', 'a-1234-bc', 'a.b.c.d.e.f');
say mask-code(@list1);
say mask-code(@list2);
sub mask-code (@list)
{
my @return;
for @list -> $string is copy
{
my $count = 0; # [2]
for ^$string.chars -> $index # [3]
{
# say ": $string + $index -> { $string.substr($index,1) } C:$count";
if $string.substr($index,1) ~~ /^ <a9> $/ # [4]
{
$string.substr-rw($index,1) = "x"; # [5]
$count++; # [2a]
last if $count == 4; # [2b]
}
}
@return.push: $string;
}
return @return;
}
[1] We set up a named regex (also called a subrule) to catch one alphanumeric character (lowercase only). It is used in [4].
See
docs.raku.org/language/regexes#index-entry-declarator_regex-Subrules
for more information about the regex
keyword.
[2] The number of characters we have replaced, starting at none. Incremented after each replacement [2a] and we stop when we have reached 4 replacements [2b].
[3] Iterate over the indices of the current string.
[4] Is the character with the current index an alphanumeric character?
[5] If yes, replace it with the character «x». Note the use of
substr-rw
, as we are changing the value, instead of substr
which is read only. Note the is copy
in the outermost for
loop, so that we actually can change the value.
See
docs.raku.org/routine/substr-rw
for more information about substr-rw
.
Uncomment the commented out line, if you want some verbose output.
Running it:
$ ./mask-code
[xx-xxe-123 xxx.xbc.420 xxxx-0010.xy]
[xxxx567.a x-xxx4-bc x.x.x.x.e.f]
Looking good. (Except the formatting; brackets instead of parens, space instead of commas, and the missing quotes.)
And that's it.