For the actual calculator, go here
It all started a few days ago, when I saw one of my friends join the following group on Facebook: Put your phone on predictive text, and type ‘41568319681′.
The purpose of this group is for you to end up with the string “I.Love.You.” on your cellphone. Being the heartless person that I am, seeing that on my cellphone made me angry. And so I’ve decided to leave a snarky comment regarding the fanpage. What would be better than to claim I’ve done what the message had asked me to, and then pretend the outcome was completely different to expected?
And so I’ve decided to check what other phrases are equivalent to the same numerical string. The smart thing to do would be to get my cellphone, type in the sequence of numbers for ‘love’ (5683) and hit the star button to flip through the different possible words in the dictionary. However, in an Alice in Wonderland-esque fashion, I’ve left my cellphone on the counter before comfortably settling on the sofa with my laptop, and so it is now unreachable. And so the nerdyy thing to do is of course to consult the internet. However, the first few google search results were highly disappointing. As far as I can tell, there is no reliable textonym calculator online. The only thing I’ve found which were of any relevance were:
- That words which are spelled by the same keys in a T9 input system are called textonym
- This obviously dead website
And so I’ve realized it is my job to go forth, and set up a new online textonym service, so that people would be able to be jerks on facebook. (Alternatively, it might be used to try and understand some confusing txt messages, but that’s not very fun.)
Actual Coding Starts Here
The first step was finding a dictionary file. While this would not be exactly the same as the cellphone dictionary, I’m guessing those things are quite standard. Googling for ‘dictionary.txt’ returns a nice first result, which I’ll be using as my dictionary. It is simply a list of valid words, one per line.
Next I created my DB table:
CREATE TABLE 'DBName'.'textonym_table'
(
'word' VARCHAR( 20 ) NOT NULL ,
'value' INT NOT NULL
)
The field ‘word’ would be used to store the word, and ‘value’ would store the key sequence as an integer.
Next I started writing helper methods.
The first one populates a global array which maps letters to their corresponding keys (eg ‘a’=>2, ‘j’=>5 etc). The lazy solution would be to just hard code an associative array with 26 entries, but that’s cheating. Instead, given a (hard coded) list of characters per key, the method goes through the alphabet and increment the key being mapped to when enough characters had been assigned. As an afterthought, I’m also mapping numbers to themselves. This might come into use if people say things along the lines of ‘g2g’. (I’m lying. I’ve added this because I have fat fingers and I tend to mistype stuff, and this was easier than adding error handling.)
function initReverseArray()
{
global $reverseT9;
$keyLetterCount = array(2=>3, 3, 3, 3, 3, 4, 3, 4);
$currentLetter = 'a';
foreach ($keyLetterCount as $key => $value)
{
for($i = 0 ; $i < $value ; $i++)
{
$reverseT9[$currentLetter] = $key;
$currentLetter = chr(ord($currentLetter) + 1);
}
}
for($i = 0 ; $i < 10 ; $i++)
$reverseT9[$i] = $i;
}
The second helper method just uses the global array we just populated in order to map a word into its numerical equivalent eg love -> 5683.
Note that it must return an actual numerical value, and not a string!
So the solution is of course to scan the string, and for each character, convert it to a digit, shift it the correct number of places (by multiplying by a power of 10) and then add it to the result.
Error handling is in the form of returning -1 if an unrecognized character has been found.
function wordToT9($word)
{
global $reverseT9;
$result = 0;
for($i = 0; $i < strlen($word) ; $i++)
{
if(!isset($reverseT9[$word[$i]]))
return -1;
$result += pow(10, strlen($word) - $i - 1) * $reverseT9[$word[$i]];
}
return $result;
}
This is all that is required for the database to be populated. All that is left now, is to loop over the dictionary, and store word/value pairs.
The following code does just that, and is lacking any form of error handling. This is bad practice.
function initDB()
{ initReverseArray();
$dblink = mysql_connect('localhost');
mysql_select_db('DBName');
$fileHandle = fopen("dictionary.txt", "r");
while (!feof($fileHandle))
{
$word = trim(fgets($fileHandle));
$t9Value = wordToT9($word);
$query = "INSERT INTO textonym_table (word, value) VALUES('$word', $t9Value )";
mysql_query($query);
}
fclose($fileHandle);
mysql_close($dblink);
}
This function is to be called exactly once. Otherwise the database would contain multiple entries for the same word.
Now everything is set up, and the only thing left to do is to query the database appropriately so that we may get our textonym.
This too is fairly trivial. As no GUI was designed for this, the request for textonym is fetched via $_GET['word'] if no such argument is provided, we gracefully terminate.
if (!isset($_GET['word']))
{
echo 'Usage: ?word=w';
}
else
{
initReverseArray();
$dblink = mysql_connect('localhost');
mysql_select_db('DBName');
$t9Value = wordToT9(strtolower($_GET['word']));
echo "Words of equal value to ".$_GET['word']." ($t9Value)<br>";
$q = sprintf("SELECT * FROM textonym_table WHERE value=%s",
mysql_real_escape_string($t9Value));
$result = mysql_query($q);
if(mysql_num_rows($result) == 0)
echo 'no matches found';
else
while ($row = mysql_fetch_assoc($result))
{
echo $row['word'];
echo '<br>';
}
mysql_close($dblink);
}
And this is it. We can now quickly and efficiently learn that 'I love you' is equivalent to 'I loud you' and that facebook is not a place where sarcasm is properly conveyed.