'莱特'程序 - 获得所有排列

时间:2015-03-19 17:24:58

标签: python permutation itertools cartesian-product

我写了一个简单的功能,将字母中的字母转换为他们的' leet'数字对应物。

def Leet(word):
    letters = list(word.lower())
    for n, letter, in enumerate(letters):
        if letter == 'o':
            letters[n]= '0'
        elif letter == 'i':
            letters[n]= '1'
        elif letter == 'z':
            letters[n]= '2'
        elif letter == 'e':
            letters[n]= '3'
        elif letter == 'a':
            letters[n]= '4'
        elif letter == 's':
            letters[n]= '5'
        elif letter == 'g':
            letters[n]= '6'
        elif letter == 't':
            letters[n]= '7'
        elif letter == 'b':
            letters[n]= '8'
    return ''.join(letters)

所以当我输入'zit'时,程序将返回'217'

我的问题是,如何更改它以便为我提供所有可能的排列('217''2it''z1t''zi7''21t'等。)?我已经阅读了itertools,但我对如何将其应用于我的功能感到难过。

3 个答案:

答案 0 :(得分:5)

首先要注意的是,您可以缩短查找次数,如下所示:

REPLACE = { letter: str(index) for index, letter in enumerate('oizeasgtb') }

def Leet2(word):
    letters = [ REPLACE.get(l, l) for l in word.lower() ]
    return ''.join(letters)

REPLACE看起来像:

{'a': '4', 'b': '8', 'e': '3', 'g': '6', 'i': '1', 
 'o': '0', 's': '5', 't': '7', 'z': '2'}

如果没有替换信,REPLACE.get(l,l)会给你回信或原始信件。

第二个观察结果是你并不真正想要排列,这是排序的变化。 ' 217'的排列。是:

>>> [ ''.join(p) for p in permutations('217') ]
['217', '271', '127', '172', '721', '712']

您真正需要的是列表的产品,该列表编码给定角色位置的所有可能选择:

[('z', '2'), ('i', '1'), ('t', '7')]

如果我还显示一些可能没有有效替换字符的可能性列表,那么它的工作原理可能会更清楚。例如'red'

[('r',), ('e', '3'), ('d',)]

现在我们需要这些选项的字符串连接产品。把它们放在一起:

from itertools import product

def Leet2Combos(word):
    possibles = []
    for l in word.lower():
        ll = REPLACE.get(l, l)
        possibles.append( (l,) if ll == l else (l, ll) )
    return [ ''.join(t) for t in product(*possibles) ]

print Leet2Combos('zit')
print Leet2Combos('red')

给出:

['zit', 'zi7', 'z1t', 'z17', '2it', '2i7', '21t', '217']
['red', 'r3d']

答案 1 :(得分:3)

使用itertools.product。另外,我建议使用dict进行映射,而不是级联if/elif

>>> from itertools import product
>>> LEET = { 'z': '2', 'i': '1', 't': '7' } # and all the others     
>>> word = "zit"
>>> [''.join(letters) for letters in product(*({c, LEET.get(c, c)} for c in word))]
['zit', 'zi7', 'z1t', 'z17', '2it', '2i7', '21t', '217']

请注意LEET.get(c, c)将从dict获取“leet”字母,或使用原始字母作为默认值。 {...}用于制作这些对集,因此对于没有替换的字母没有重复。在旧版本的Python中,您可能不得不使用set([...])

相当复杂的product(*...)行大致如下:

    product(*({c, LEET.get(c, c)} for c in 'zit'))
==> product(*({'z', LEET.get('z', 'z')}, {'i', LEET.get('i', 'i')}, {'t', LEET.get('t', 't')}))
==> product(*({'z', '2'}, {'i', '1'}, {'t', '7'}))
==> product(  {'z', '2'}, {'i', '1'}, {'t', '7'} )

产生所有这些字母的cartesian product及其替代品。

答案 2 :(得分:0)

一种方法是使用itertools.product,如你所提到的,它将执行列表的笛卡尔积。

问题是要有这个列表,每个组合,例如zit列表应该是:

[['z', '2'], ['i', '1'], ['t', '7']]

我的代码:

import itertools

def leet(word):
    leet_matches = [['a', '4'],
    ['b' ,'8'],
    ['c'],
    ['d'],
    ['e', '3'],
    ['f'],
    ['g', '6'],
    ['h'],
    ['i', '1'],
    ['j'],
    ['k'],
    ['l'],
    ['m'],
    ['n'],
    ['o', '0'],
    ['p'],
    ['q'],
    ['r'],
    ['s', '5'],
    ['t', '7'],
    ['u'],
    ['v'],
    ['w'],
    ['x'],
    ['y'],
    ['z', '2']]
    l = []
    for letter in word:
        for match in leet_matches:
            if match[0] == letter:
                l.append(match)
    return list(itertools.product(*l))

print leet("zit")

请注意,使用列表(或元组)而不是Dict,您可以对一个字母进行多次替换,例如: " I"可以成为" 1"或"!"