Skip to content

Instantly share code, notes, and snippets.

@JohnMertz

JohnMertz/dialpad.pl

Created Apr 10, 2020
Embed
What would you like to do?
Translate letters to dialpad numbers and numbers to possible words
#!/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
You can’t perform that action at this time.