开发者

Finding All Possible Combinations of Letters using an API and Python

I'm trying to put together a small web app where users enter in the last 4 digits of their phone number, hit submit, and then are shown all the words (if any) that can be made on the keypad using their 4 numbers. So if a user enters "2287" they are shown "acts" "bats" "cats" and any other words that can be made from the combination of "a / b / c" and "a / b / c" and "t / u / v" and "p / q / r / s".

I'm new to web apps and web scripting but I've figured out how to do most of the steps involved. The problems I'm having are:

  1. Creating all possible combinations of the letters

  2. Figuring out which combinations are actually words

I would think you could do some of this using an API but I don't know where to look for something like that. If I used a some sort dictionary API could I enter in all the possible combinations at once, or would I have to make (roughly) 81 different API calls to check if each combination is a real word.

I'm obviously a pretty big noob when it comes to stuff like this, but I'm trying to 开发者_JAVA百科start off with something simple like this to try and get myself acquainted with server-side web scripting. Also, if at all possible, It'd be awesome if I everything was done in Python as that is the language we are using in my internet applications class and it would make sense to just stick with one language at first. Anyways, thanks in advance.


Read dictionary and keep only 4 letter words, append them to defaultdict(list) by the number code of the four letters, when user inputs for numbers give them the ready list for that number or say 'No words for that number'.

import itertools
letters = ('',' ', 'abc','def','ghi','jkl','mno','pqrs','tuv','wxyz')
reverse_dict = dict((str(ind), group)
                    for ind,group in enumerate(letters)
                    for c in group
                    if letters)

print reverse_dict
end_nums = '3965'
print end_nums, 'can produce', tuple(''.join(w) for w in itertools.product(*map(reverse_dict.get, end_nums)))
word = 'word'
print('%r = %s' % (word,''.join(key for c in word for key, item in reverse_dict.items() if c in item)))


A naive approach would be

import itertools

letters = ('','','abc','def','ghi','jkl','mno','pqrs','tuv','wxyz')
good_words = set(['wall','base','cats'])  # etc

def allWords(s):
    s = [int(ch) for ch in s.zfill(4)]
    for word in itertools.product(letters[s[0]], letters[s[1]], letters[s[2]], letters[s[3]]):
        word = ''.join(word)
        if word in good_words:
            yield word

words = list(allWords('2297'))

A more efficient one would preprocess all good words into a dictionary of per-telephone-number lists and just do a lookup:

import string
import collections

class CodingError(Exception):
    pass

class TelephoneWords(object):
    numbers = {
        'a': '2', 'b': '2', 'c': '2', 'd': '3',
        'e': '3', 'f': '3', 'g': '4', 'h': '4',
        'i': '4', 'j': '5', 'k': '5', 'l': '5',
        'm': '6', 'n': '6', 'o': '6', 'p': '7',
        'q': '7', 'r': '7', 's': '7', 't': '8',
        'u': '8', 'v': '8', 'w': '9', 'x': '9',
        'y': '9', 'z': '9', '0': '0', '1': '1',
        '2': '2', '3': '3', '4': '4', '5': '5',
        '6': '6', '7': '7', '8': '8', '9': '9'
    }
    wordlen = 4

    def __init__(self, wordlist=None, fname=None):
        super(TelephoneWords,self).__init__()
        self.words = collections.defaultdict(list)
        if wordlist:
            self.addwords(wordlist)
        if fname:
            with open(fname) as inf:
                filestr = ' '.join(inf.readlines()).replace(string.punctuation, ' ')
                self.addwords(filestr.split())

    def addwords(self, words):
        _wordlen = TelephoneWords.wordlen
        _words   = self.words
        _encode  = self.encode
        for word in words:
            if len(word)==_wordlen:
                word = word.lower()
                try:
                    _words[_encode(word)].append(word)
                except CodingError:
                    pass

    def addword(self, word):
        self.addwords((word,))

    def encode(self, s):
        _numbers = TelephoneWords.numbers
        res = []
        for ch in s:
            try:
                res.append(_numbers[ch])
            except KeyError:
                # no corresponding value found
                raise CodingError("No value available for char '{0}'".format(ch))
        return ''.join(res)

    def seek(self, num):
        s = str(num).strip().zfill(TelephoneWords.wordlen)
        try:
            return self.words[s]
        except KeyError:
            raise ValueError("No words found for '{0}'".format(s))

    def find(self, num, onErr=None):
        try:
            return self.seek(num)
        except ValueError:
            return [] if onErr is None else onErr

def main():
    tw = TelephoneWords(fname='four_letter_words.txt')

    for word in tw.find('2287'):
        print word

if __name__=="__main__":
    main()

Using a Scrabble wordlist, this gives me

acts
bats
baur
cats
caup
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜