按顺序生成字母数字字符串

8
我正在尝试创建一个循环来生成并打印字符串,如下所示:
  1. 仅包含字母数字字符:
  2. 0-9在A-Z之前,在a-z之前,
  3. 长度最多为4个字符。
因此,它将打印出:
  1. 从0到z的所有字符串
  2. 然后是从00到zz的所有字符串
  3. 然后是从000到zzz的所有字符串
  4. 然后是从0000到zzzz的所有字符串
然后停止。

你的问题太难理解了... a07z 是一个合法的字符串吗? - immortal
是的。所有长度为1-4的字母数字字符串都是合法的。 - joseph
当你说0-9在A-Z之前时,你的意思是0000应该在A000之前吗? - immortal
5个回答

24
from string import digits, ascii_uppercase, ascii_lowercase
from itertools import product

chars = digits + ascii_uppercase + ascii_lowercase

for n in range(1, 4 + 1):
    for comb in product(chars, repeat=n):
        print ''.join(comb)

首先,它将所有数字、大写字母和小写字母组成一个字符串。

然后,对于每个长度为1-4的字符串,它打印出由这些数字和字母组成的所有可能组合。

请记住,这是非常多的组合——62^4 + 62^3 + 62^2 + 62。


这是一个很棒的解决方案。另一个很棒的做法是将其制作为生成器而不是直接打印字符串。 - Drekembe
我知道这有很多组合,我主要是为了测试目的而这样做的。我将其从4个字符减少到3个字符。 - joseph
是的,他说他想要一个“打印字符串的循环”,所以我就给了他这个。 - agf
请注意:ascii_lowercase + ascii_uppercase == ascii_letters - Błażej Michalik

1
from string import digits, ascii_uppercase, ascii_lowercase
from itertools import product
chars = digits + ascii_uppercase + ascii_lowercase

def give_me_next(lst):
        lst = lst[::-1]
        change_next = False
        change = True
        n = 0
        for x in lst:
                if change_next == True:
                        change_next = False
                        pos = chars.find(x)
                        try:
                                a =  chars[pos+1]
                                lst = list(lst)
                                lst[n] = a
                                lst = "".join(lst)
                                x = a
                        except:
                                lst = list(lst)
                                lst[n] = '0'
                                lst = "".join(lst)
                                change_next = True
                                x = '0'

                pos = chars.find(x)
                try:
                        a =  chars[pos+1]
                        if change == True:
                                lst = list(lst)
                                lst[n] = a
                                lst = "".join(lst)
                                change = False
                except:
                        lst = list(lst)
                        lst[n] = '0'
                        lst = "".join(lst)
                        change_next = True

                n = n + 1

        lst = lst[::-1]
        return lst

a=  give_me_next('zzzzz')
while True:
        a =  give_me_next(a)
        print a

0

对我来说,这似乎是最简单的解决方案:

from string import digits, ascii_uppercase, ascii_lowercase

chars = digits + ascii_uppercase + ascii_lowercase
all_str = [''.join([a]) for a in chars] \
        + [''.join([a,b]) for a in chars for b in chars] \
        + [''.join([a,b,c]) for a in chars for b in chars for c in chars] \
        + [''.join([a,b,c,d]) for a in chars for b in chars for c in chars for d in chars]

print(all_str)
print("Number of strings:", len(all_str))

最多包含2个字符的字符串示例。

当然,可能有一种方法可以将每个字符串的最大字符数推广到任意数量,但由于您需要处理长度不超过4个字符的字符串,所以这样做是可以的。


0

我今天编写了这段代码。它完全符合你的要求并且更多。它还可以扩展。

def lastCase (lst):
    for i in range(0, len(lst)):
        if ( lst[i] != '_' ):
            return False
    return True


l = [''] * 4 #change size here if needed. I used 4
l[0] = '0'
index = 0

while ( not lastCase(l) ):

    if ( ord(l[index]) > ord('_') ):
        l[index] = '0'
        index += 1
        while( l[index] == '_' ):
            l[index] = '0'
            index += 1
        if (l[index] == ''):
            l[index] = '0'

    #print or process generated string
    print(''.join(l))

    l[index] = chr(ord(l[index]) +1)

    if ( ord(l[index]) > ord('9') and ord(l[index]) < ord('A') ):
        l[index] = 'A'
    elif ( ord(l[index]) > ord('Z') and ord(l[index]) < ord('_')  ): 
        l[index] = '_'

    index = 0

print (''.join(l))

0

我不喜欢之前给出的答案,使用 product ,因为看了它在 Python 文档中的实现似乎会将整个东西拓展到一个列表中并在开始生成结果之前占用很多内存。

对于这种情况来说非常糟糕,因为正如 agf 自己所说,这里的排列组合数非常大(超过一百万)。对于这种情况,yield 语句被创建出来 - 这样就可以动态地生成庞大的列表,而不是在内存中进行扩展(我也不喜欢浪费性能的 range ,这时候应该使用适用于此的 xrange )。

我会选择这样的解决方案:

def generate(chars, length, prefix = None):
    if length < 1:
        return
    if not prefix:
        prefix = ''
    for char in chars:
        permutation = prefix + char
        if length == 1:
            yield permutation
        else:
            for sub_permutation in generate(chars, length - 1, prefix = permutation):
                yield sub_permutation

这种方式,所有在内存中的内容都是一个递归栈,深度为“n”,其中“n”是您的排列长度(在本例中为4),每次仅返回单个元素。

chars是要选择的字符集,长度为4,使用方式与products相似,但在运行时不会在内存中跨越整个列表。


2
在“product”描述中写道:“该函数等效于以下代码,仅是实际实现不会在内存中构建中间结果:”itertools中的所有工具都是这样工作的,这是该模块的整个目的。 - agf
我认为对于非常小的范围,range 实际上比 xrange 更节省资源。 - agf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接