Peter Campbell Smith

Manipulating characters

Weekly challenge 185 — 3 October 2022

Week 185 - 3 Oct 2022

Task 2

Task — Mask code

You are given a list of codes in a random format. Write a script to mask first four characters which are (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')


Examination of the examples suggests that we are given an arbitrary string of characters, and are required to change the first 4 instances of [a-z0-9] to 'x'.

Again a solution using a regular expression can do the work in a single line: s|^(.*?)[a-z0-9](.*?)[a-z0-9](.*?)[a-z0-9](.*?)[a-z0-9]|$1x$2x$3x$4x|

That's a little hard to read, but essentially it breaks the string at the four characters of interest and the (possibly empty) substrings in between them, and then joins the latter up with 'x's.

For this to work I am taking the hard line that any valid input to the task has at least 4 characters matching [a-z0-9]. If that assertion fails, then I think the single regular expression has to be replaced with a loop over 4 attempts to replace one character with 'x'.

But what if one of the first four [a-z0-9] characters in the string is already 'x'? Are we to ignore it or process it:

axbcdef -> xxxxxef or axbcdef -> xxxxdef ?

The first of these fails the task criteria because it has masked the fifth [a-z0-9] character in violation of 'mask the first four and keep the rest'. The second of these fails the criteria because the second character in the string is 'x' before and after and is therefore not masked, violating 'mask the first four'.

So, obliquely, I think we can say that none of the first four [a-z0-9] characters in the string can be 'x'.

Try it 

Try running the script with any input:

example: 'ab-cde-123', '', '3abc-0010.xy'



# Peter Campbell Smith - 2022-10-02
# PWC 185 task 1

use v5.28;
use utf8;
use warnings;
binmode(STDOUT, ':utf8');

my (@tests, $test, @list, $item, $j, $output);

@tests = (['ab-cde-123', '', '3abc-0010.xy'], 
    ['A5h&kP.....z', '!"£$%^&*()', 'xxxx00000', 'abcd', 'ǀØΨ£‡⁇ aaaa']);

# loop over tests
for $test (@tests) {
    @list = @$test;
    # initialise
    say qq[\nInput: \@list = (] . join(', ', @list) . ')';
    $output = '';
    # loop over items within test
    for $item (@list) {
        $item =~ s|^(.*?)[a-z0-9](.*?)[a-z0-9](.*?)[a-z0-9](.*?)[a-z0-9]|$1x$2x$3x$4x|;
        $output .= qq[$item, ];
    # and print the answer
    say qq[Output:        (] . substr($output, 0, -2) . ')';


Input: @list = (ab-cde-123,, 3abc-0010.xy)
Output:        (xx-xxe-123, xxx.xbc.420, xxxx-0010.xy)

Input: @list = (A5h&kP.....z, !"£$%^&*(), xxxx00000, abcd, ǀØΨ£‡⁇ aaaa)
Output:        (Axx&xP.....x, !"£$%^&*(), xxxx00000, xxxx, ǀØΨ£‡⁇ xxxx)

The content of this website which has been created by
Peter Campbell Smith is hereby placed in the public domain