GSTrans string conversion

# 20231105 Raku programming solution

sub GSTrans-encode(Str $str) {
   return [~] $str.encode('utf8').list.chrs.comb.map: -> $c { 
      my $i = $c.ord;
      die "Char value of $c, $i, is out of range" unless 0 <= $i <= 255;
      given ($i,$c) { 
         when 0 <= $i <= 31    { '|' ~ chr(64 + $i) } 
         when $c eq '"'        { '|"' }
         when $c eq '|'        { '||' }
         when $i == 127        { '|?' }
         when 128 <= $i <= 255 { '|!' ~ GSTrans-encode(chr($i - 128)) }
         default               { $c }
      }
   }
}

sub GSTrans-decode(Str $str) {
   my ($gotbar, $gotbang, $bangadd) = False, False, 0;

   my @result = gather for $str.comb -> $c {
      if $gotbang {
         if $c eq '|' {
            $bangadd = 128;
            $gotbar = True;
         } else {
            take $c.ord + 128;
         }
         $gotbang = False;
      } elsif $gotbar {
         given $c {
            when $c eq '?' { take 127 + $bangadd }
            when $c eq '!' { $gotbang = True }
            when $c eq '|' || $c eq '"' || $c eq '<' { take $c.ord + $bangadd }
            when $c eq '[' || $c eq '{' { take 27 + $bangadd } 
            when $c eq '\\' { take 28 + $bangadd } 
            when $c eq ']' || $c eq '}' { take 29 + $bangadd } 
            when $c eq '^' || $c eq '~' { take 30 + $bangadd }
            when $c eq '_' || $c eq '`' { take 31 + $bangadd }
            default { my $i = $c.uc.ord - 64 + $bangadd;
                      take $i >= 0 ?? $i !! $c.ord      }
         }
         $gotbar = False;
         $bangadd = 0;
      } elsif $c eq '|' {
         $gotbar = True
      } else {
         take $c.ord
      }
   }
   return Blob.new(@result).decode('utf8c8')
}

my @TESTS = <ALERT|G 'wert↑>;
my @RAND_TESTS = ^256 .roll(10).chrs.join xx 8;
my @DECODE_TESTS = < |LHello|G|J|M |m|j|@|e|!t|m|!|? abc|1de|5f >; 

for |@TESTS, |@RAND_TESTS -> $t {
   my $encoded = GSTrans-encode($t);
   my $decoded = GSTrans-decode($encoded);
   say "String $t encoded is: $encoded, decoded is: $decoded.";
   die unless $t ~~ $decoded;
}
for @DECODE_TESTS -> $enc {
    say "Encoded string $enc decoded is: ", GSTrans-decode($enc);
}

You may Attempt This Online!

Last updated