Created
April 10, 2020 11:53
-
-
Save JohnMertz/02165aa0803c5348446010d71556f37a to your computer and use it in GitHub Desktop.
Translate letters to dialpad numbers and numbers to possible words
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
# TODO: at the moment, words are only broken up by 0 and 1. Should search for smaller sequential words. For example: | |
# 6908378 finds: mytest | |
# but 1698378 does not | |
use strict; | |
use warnings; | |
# Default Debian ispell dictionary | |
my $dict = "/etc/dictionaries-common/words"; | |
my %dialpad = ( | |
2 => 'abc', | |
3 => 'def', | |
4 => 'ghi', | |
5 => 'jkl', | |
6 => 'mno', | |
7 => 'pqrs', | |
8 => 'tuv', | |
9 => 'wxyz' | |
); | |
my $numbers = ''; | |
my $letters = ''; | |
foreach (@ARGV) { | |
# All letters appended to list | |
if ($_ =~ m/^[a-zA-Z]+$/ && !$numbers) { | |
$letters = $_; | |
# All numbers appended to list | |
} elsif ($_ =~ m/^[0-9\.\*]+$/ && !$letters) { | |
$numbers .= $_; | |
# Non-alphabetical characters or a mix, throw error. | |
} else { | |
print "Invalid argument: $_\n"; | |
usage(); | |
} | |
} | |
# If no argument, die | |
unless ($letters || $numbers) { | |
print "No input letters or numbers to evaluate\n"; | |
usage(); | |
} | |
# Translating letters to numbers is dead simple with regex | |
if ($letters) { | |
foreach my $key (keys %dialpad) { | |
$letters =~ s/[$dialpad{$key}]/$key/g; | |
} | |
print $letters . "\n"; | |
exit; | |
} | |
# Finding words for numbers is a little less simple... | |
# First, convert all numbers to regex | |
foreach my $key (keys %dialpad) { | |
$numbers =~ s/$key/\[$dialpad{$key}\]/g; | |
} | |
# Then, since 0 and 1 have no equivalent letters, split the regex into array | |
my @blocks = ( $numbers =~ /([^01]*)([01]?)/g ); | |
# Load dictionary into memory | |
open my $fh, '<', $dict; | |
my @words; | |
while (<$fh>) { | |
push @words, $_; | |
} | |
close $fh; | |
# Cycle through and collect options for each | |
my @options = (); | |
my $ctr = 0; | |
foreach (@blocks) { | |
@{$options[$ctr]} = (); | |
if (!$_) { | |
next; | |
} elsif ($_ eq 0 || $_ eq 1) { | |
@{$options[$ctr]} = ( "$_" ); | |
} else { | |
foreach my $word (@words) { | |
chomp $word; | |
if ($word =~ m/^$_$/) { | |
push @{$options[$ctr]}, $word; | |
} | |
} | |
} | |
if (scalar @{$options[$ctr]}) { | |
$ctr++; | |
} | |
} | |
unless ($ctr) { | |
die "Didn't find any words that match\n"; | |
} | |
my @all = @{shift @options}; | |
while (scalar @options) { | |
if (my @next = @{shift @options}) { | |
@all = combine(\@all,\@next); | |
} | |
} | |
foreach (@all) { | |
print $_ . "\n"; | |
} | |
sub combine { | |
my ($a, $b) = @_; | |
my @c = (); | |
foreach my $first (@{$a}) { | |
foreach my $second (@{$b}) { | |
push @c, $first.$second; | |
} | |
} | |
return @c; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment