I’ve been doing the Perl Weekly
Challenges. Last week's was about
encoding and decoding to a binary representation of Morse code.
This isn't one I've met before: a dot is 1, a dash is 111, an
inter-dot/dash gap is 0, an inter-letter gap is 000, and an inter-word
gap is 0000000.
The first step was to get the code table into memory; in perl5 I
pulled it from a __DATA__ block, in perl6 I just defined it as a
hash, but in each case it's a set of letter keys to dot/underscore
values.
Next build a binary encoding table:
my %e;
foreach my $char (keys %t) {
$e{$char}=join('0',map {{'.' => '1',
'_' => '111'}->{$_}}
split '',$t{$char});
}
Sanitise the input to the allowed character set (things for which
encodings exist, and spaces):
my $chars=join('',keys %t);
my @in;
while (<>) {
chomp;
my $t=uc($_);
$t =~ s/[^ $chars]//g;
push @in,$t;
}
Then encode, building up words from characters and the message from words.
my $m=join(' ',@in);
my @l;
foreach my $word (split ' ',$m) {
my @w;
foreach my $char (split '',$word) {
push @w,$e{$char};
}
push @l,join('000',@w);
}
print join('0000000',@l),"\n";
Perl6 is very similar, except that its split
puts spurious empty
strings at the beginning and end of the output list; it may well be
that comb
is a better option here, but it looks distinctly fiddly.
To decode, I build a decoding table:
my %d;
foreach my $char (keys %t) {
$d{join('0',map {{'.' => '1',
'_' => '111'}->{$_}}
split '',$t{$char})}=$char;
}
Then take the message, break it down to words and to characters, then
decode individual characters as far as possible. Perl6 varies only in
details of syntax.
my @in;
while (<>) {
chomp;
push @in,$_;
}
my $m=join('',@in);
my @m;
foreach my $word (split /0000000+/,$m) {
my @w;
foreach my $char (split /000+/,$word) {
push @w,($d{$char} or '?');
}
push @m,join('',@w);
}
print join(' ',@m),"\n";
I also wrote a program to make random substitutions into the bit
stream to see how the decoder would cope with corruption; it seems to
do reasonably well, given the lack of redundancy in the encoding.
Comments on this post are now closed. If you have particular grounds for adding a late comment, comment on a more recent post quoting the URL of this one.