# Perl Weekly Challenge 186.

My solutions (task 1 and task 2 ) to the The Weekly Challenge - 186.

``````Submitted by: Mohammad S Anwar
You are given two list @a and @b of same size.

Create a subroutine sub zip(@a, @b) that merge the two list as shown in the example below.

Example
Input:  @a = qw/1 2 3/; @b = qw/a b c/;
Output: zip(@a, @b) should return qw/1 a 2 b 3 c/;
zip(@b, @a) should return qw/a 1 b 2 c 3/;
``````

The easy way out is to use a canned solution, such as `zip` from `List::MoreUtils`. I assume that the lists are provided as space separated strings in @ARGV;

``````perl -MList::MoreUtils=zip -E '@x=split " ", shift;@y=split " ", shift; say join " ", zip @x, @y;
' "1 2 3" "a b c"
``````

Results:

``````1 a 2 b 3 c
``````

A solution may be built from scratch using perl prototypes to convert input arrays to input array references.

``````perl -E 'sub zip :prototype(\@\@) (\$x,\$y){while(@\$x or @\$y){push @r, shift @\$x, shift @\$y}
grep {defined} @r} @x=split " ", shift;@y=split " ", shift; say join " ", zip(@x, @y);
' "1 2 3" "a b c"
``````

Results:

``````1 a 2 b 3 c
``````

The behaviour for lists of uneven length is not well defined. Here I followed the same convention as in `List::MoreUtils`, i.e., if one list is exhausted I just add the elements of the other list. Actually, I continue zipping `undef`’s and I `grep` them out at the end.

The full code is

`````` 1  # Perl weekly challenge 186
2  # Task 1:  Zip List
3  #
5  use v5.36;
6  sub zip :prototype(\@\@) (\$x,\$y){
7      my @result;
8      while(@\$x or @\$y){ # Until both lists are exhausted
9          push @result, shift @\$x, shift @\$y
10      }
11      grep {defined} @result  # remove undef's
12  }
13  die qq/Usage: \$0 "x1 x2..." "y1 y2..."\nto zip two lists/ unless @ARGV==2;
14  my @x=split " ", shift;
15  my @y=split " ", shift;
16  say join " ", zip(@x, @y);
``````

Example:

``````./ch-1.pl "1 2 3" "a b c"
``````

``````Submitted by: Mohammad S Anwar
You are given a string with possible unicode characters.

Create a subroutine sub makeover(\$str) that replace the unicode characters
with ascii equivalent. For this task, let us assume it only contains alphabets.

Example 1
Input: \$str = 'ÃÊÍÒÙ';
Output: 'AEIOU'
Example 2
Input: \$str = 'âÊíÒÙ';
Output: 'aEiOU'
``````

I’m always very confused by Unicode and Perl. I assume that the input strings are given in `@ARGV`. Since they contain unicode strings, I first decode them. I split them into chars and compare them using Unicode::Collate to the printable ASCII characters, ignoring all kind of accents. If they match, they are replaced. Finally, I encode and print the resulting string. The result fits a three-liner.

``````perl -MEncode=decode,encode -MUnicode::Collate -E '
sub r(\$x){state \$c=Unicode::Collate->new(level=>3, ignore_level2=>1); \$c->cmp(\$_, \$x)==0
&& return \$_ for map {chr} (0x20..0x7e); \$x;}sub makeover(\$s){join "", map {r \$_}
split "", \$s} say encode("UTF-8", makeover(decode("UTF-8", \$_))) for(@ARGV);
'  ÃÊÍÒÙ âÊíÒÙ
``````

Results:

``````AEIOU
aEiOU
``````

Maybe it is inefficient to check all ASCII chars instead of checking all possible accents and ornaments, but I don’t know how many of those there are.

The full code is

`````` 1  # Perl weekly challenge 186
2  # Task 2:  Unicode Makeover
3  #
5  use v5.36;
6  use Encode qw(decode encode);
7  use Unicode::Collate;
8  sub char2ascii(\$char){ # Convert single char to ascii
9      state \$coll=Unicode::Collate->new(level=>3, ignore_level2=>1); #Ignore accents, check case
10      state @ascii=map {chr} (0x20..0x7e);
11      \$coll->cmp(\$_, \$char)==0 && return \$_ for @ascii; #return ascii if found
12      \$char # default
13  }
14
15  sub makeover(\$string){ # convert string to ascii
16      join "", map {char2ascii \$_} split "", \$string
17  }
18
19  die "Usage: \$0 S1 [S2...]\nto convert strings S1 S2 etc. to ascii" unless @ARGV;
20  say encode("UTF-8", makeover(decode("UTF-8", \$_))) for(@ARGV);
``````

Example:

``````./ch-2.pl ÃÊÍÒÙ âÊíÒÙ
``````

Results:

``````AEIOU
aEiOU
``````

Curiously, my code above maps many punctuation characters to space, though they are ASCII punctuation. I guess that at level 3 all punctuation is equivalent.

``````./ch-2.pl ".,;:{}[]+=?!¿¡﹋"|od -h
``````

Results:

``````0000000 2020 2020 2020 2020 2020 2020 2020 0a20
0000020
``````
Written on October 10, 2022