PWC185 - Mask Code


On with TASK #2 from The Weekly Challenge #185. Enjoy!

The challenge

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

The questions

Just a few annoyances…

  • confirmation: are we using x to conceal x?
  • What if there are not enough characters to mask?

The solution

There are times for clever solutions that take a smart regular expression and provide a way to impress the others.

There are other times where you can’t come up with any, so you just decide to go one character at a time and call it a day. Which, to be honest, I find super-clever because, you know, readability.

So, as we’re going for readability here, I’ll call also insecure week and get rid of strict and warnings again, just because I like living on the edge.

#!/usr/bin/env perl

say for mask_code(qw< ab-cde-123 3abc-0010.xy
   1234567.a a-1234-bc a.b.c.d.e.f >);

sub mask_code {
   state $is_target = { map { $_ => 1 } ('0' .. '9', 'a' .. 'z') };
   map {
      my $copy = $_;
      my ($i, $I, $n) = (0, length($copy), 0);
      while ($n < 4 && $i < $I) {
         if ($is_target->{substr $copy, $i, 1}) {
            substr $copy, $i, 1, 'x';
   } @_;

I’m not sure whether I’m prematurely optimizing here with the test about applicable characters using a state hash reference. I mean, a regular expression would have worked fine too:

if (substr($copy, $i, 1) =~ m{[a-z0-9]}mxs) { ...

Anyway, life is full of decisions.

Translation to Raku made me trip over a flat, once again. I really need to remember to tidy up my flat.

#!/usr/bin/env raku
use v6;
sub MAIN {
   .put for mask-code(< ab-cde-123 3abc-0010.xy
   1234567.a a-1234-bc a.b.c.d.e.f >);

sub mask-code (@list) {
   state %is-target = ('0' .. '9', 'a' .. 'z') * => 1; -> $s is copy {
      my ($i, $I, $n) = (0, $s.chars, 0);
      while $n < 4 && $i < $I {
         if %is-target{$s.substr($i, 1)} {
            $s.substr-rw($i, 1) = 'x';

As a final suggestion… don’t do like me.

use strict.

use warnings.

Stay safe!

Comments? Octodon, Twitter, GitHub, Reddit, or drop me a line!