/** * Copyright: Copyright (c) 2008 Jacob Carlborg. All rights reserved. * Authors: Jacob Carlborg * Version: Initial created: May 27, 2008 * License: $(LINK2 http://opensource.org/licenses/bsd-license.php, BSD Style) * */ module phonecode; import tango.core.Array; import tango.io.FileConduit; import tango.io.Stdout; import Ascii = tango.text.Ascii; import tango.text.Regex; import tango.text.stream.LineIterator; import tango.time.StopWatch; import tango.time.Time; char[char] map; string[][string] hash; int minWordLength; string[] words; /** * Prints to standard output * and adds a new line * * Params: * args = what to print */ void println (A...) (A args) { foreach (a ; args) Stdout(a); Stdout.newline; } /** * Initiates necessery action in order to search for words. * Calulates min wordlength and saves words to hashtable * * Params: * words = the array of words */ void init (string[] words) { map = ['a' : '5', 'b' : '7', 'c' : '6', 'd' : '3', 'e' : '0', 'f' : '4', 'g' : '9', 'h' : '9', 'i' : '6', 'j' : '1', 'k' : '7', 'l' : '8', 'm' : '5', 'n' : '1', 'o' : '8', 'p' : '8', 'q' : '1', 'r' : '2', 's' : '3', 't' : '4', 'u' : '7', 'v' : '6', 'w' : '2', 'x' : '2', 'y' : '3', 'z' : '9']; .words = words; debug println("Calculates minimal wordlength"); calcMinWordLength; debug println("Saves words in hashtable"); toHash; } /** * Converts the given char to lowercase * * Params: * c = the char to convert * * Returns: the converted char */ char toLower (char c) { return Ascii.toLower([c])[0]; } /** * Method that tries to find all possible * word replacements for the digits in number. * * Params: * number = the number to find all the words for * * Returns: an array with all possible word replacements */ string[] findWords (string number) { return findWordsRec(number, true); } /** * Method that tries to find all possible * word replacements for the digits in number. * * Params: * number = the number to find all the words for * replaceWithNumb = argument used in recursive calls to prevent two digits after each other * * Returns: an array with all possible word replacements */ string[] findWordsRec (string number, bool replaceWithNumb) { string[] arrRet; if (number.length == 0) return [""]; else { if (minWordLength - 1 < number.length) { if (number[0 .. minWordLength - 1] in hash) { string[] arr = hash[number[0 .. minWordLength - 1]]; foreach (dicWord ; arr) { auto dicWordNumb = stringToNumb(dicWord); if (Regex(dicWordNumb).test(number)) { auto tail = findWordsRec(number[dicWord.length .. $], true); foreach (t ; tail) arrRet ~= dicWord ~ " " ~ t; } } } } else { if (number[0 .. $] in hash) { string[] arr = hash[number[0 .. minWordLength - 1]]; foreach (dicWord ; arr) { auto dicWordNumb = stringToNumb(dicWord); if (Regex(dicWordNumb).test(number)) { auto tail = findWordsRec(number[dicWord.length .. $], true); foreach (t ; tail) arrRet ~= dicWord ~ " " ~ t; } } } } } if (arrRet.length == 0 && replaceWithNumb == true) { auto tail = findWordsRec(number[1 .. $], false); foreach (t ; tail) arrRet ~= number[0 .. 1] ~ " " ~ t; } auto i = arrRet.unique(); return arrRet[0 .. i]; } /** * Converts str to numbers according to map * * Params: * str = the string to convert * * Returns: the convertet string */ string stringToNumb (string str) { string ret; foreach (c ; str) ret ~= map[toLower(c)]; return ret; } /** * Makes a hashtable where the values are arrays with words whos first letters translates to the key * How many letter that are used as key depends on how long the shortaged word in file is * ex. the word 'hello' is in an array where the key is 90 as h=9 and e=0 and the shortest word in file is 2 characters long */ void toHash () { string[][string] h; foreach (word ; words) { auto x = stringToNumb(word); x = x[0 .. minWordLength - 1]; if (!(x in h)) h[x] = [word]; else h[x] ~= word; } hash = h; } /// Calculates the minimal word length void calcMinWordLength () { auto ret = 1000; foreach (word ; words) if (word.length < ret) ret = word.length; minWordLength = ret; } void main (string[] args) { if (args.length == 3) { StopWatch elapsed; elapsed.start; string[] words; auto filenameNumbers = new FileConduit(args[1]); auto filenameWords = new FileConduit(args[2]); scope (exit) { filenameNumbers.close; filenameWords.close; } auto numbersLineIterator = new LineIterator!(char)(filenameNumbers); auto wordsLineIterator = new LineIterator!(char)(filenameWords); foreach (word ; wordsLineIterator) words ~= word.dup; init(words); foreach (number ; numbersLineIterator) { auto ret = findWords(number); foreach (re ; ret) println(number, ": ", re); } auto time = TimeSpan.micros(elapsed.microsec); println("time: \n", time.hours, " hours\n", time.minutes, " minutes\n", time.seconds, " seconds\n", time.millis, " milliseconds\n", time.micros, " microseconds\n", time.nanos, " nanoseconds\n"); } else println("usage: phonecode numbers words"); }