2010-07-16 7 views
5

In perl, per ottenere un elenco di tutte le stringhe da "a" a "azc", l'unica cosa da fare è utilizzare l'operatore intervallo:Qual è l'equivalente python di perl "a" .. "azc"

perl -le 'print "a".."azc"' 

Quello che voglio è una lista di stringhe:

["a", "b", ..., "z", "aa", ..., "az" ,"ba", ..., "azc"] 

suppongo posso usare ord e chr, loop più e più volte, questo è semplice da ottenere per "a" alla "z", ad esempio, :

>>> [chr(c) for c in range(ord("a"), ord("z") + 1)] 
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] 

Ma un po 'più complesso per il mio caso, qui.

Grazie per qualsiasi aiuto!

risposta

4

Generator:

from string import ascii_lowercase 
from itertools import product 

def letterrange(last): 
    for k in range(len(last)): 
     for x in product(ascii_lowercase, repeat=k+1): 
      result = ''.join(x) 
      yield result 
      if result == last: 
       return 

EDIT: @ihightower chiede nei commenti:

Non ho idea di cosa dovrei fare se voglio stampare da 'b' a 'azc'.

Quindi si desidera iniziare con qualcosa di diverso da 'a'. Basta scartare nulla prima che il valore iniziale:

def letterrange(first, last): 
    for k in range(len(last)): 
     for x in product(ascii_lowercase, repeat=k+1): 
      result = ''.join(x) 
      if first: 
       if first != result: 
        continue 
       else: 
        first = None 
      yield result 
      if result == last: 
       return 
+0

sì! Decisamente buono (non posso votare dato che ho solo 11 reputazione, ma ho ragione!) –

+0

Ottima risposta Mike! – ninetwozero

+0

Potrebbe essere un'ottima risposta ... Ma, come si usa questo ... Come novizio ... Non ho idea di cosa dovrei fare se voglio stampare da 'b' a 'azc'. Ripeto dalla lettera "b" alla lettera "azc". La funzione potrebbe essere buona ... ma come principiante non ho idea di come potrei usarlo per fare il lavoro e stampare. – ihightower

2

Utilizzare la chiamata del prodotto in itertools e ascii_letters dalla stringa.

from string import ascii_letters 
from itertools import product 

if __name__ == '__main__': 
    values = [] 
    for i in xrange(1, 4): 
     values += [''.join(x) for x in product(ascii_letters[:26], repeat=i)] 

    print values 
+0

Dovrebbe essere 'ascii_lowercase', e non hanno ancora contabilizzati fermandosi a 'AZC'. –

+0

hmm, grazie, qui posso avere una lista di stringhe da a a zzz. Quindi farò un secondo ciclo per copiare gli elementi dal primo loop al secondo, e fermarmi mentre incontriamo la stringa "end". Risponderò alla mia domanda con un esempio di codice completo. Molte grazie ! –

0
def strrange(end): 
    values = [] 
    for i in range(1, len(end) + 1): 
     values += [''.join(x) for x in product(ascii_lowercase, repeat=i)] 
    return values[:values.index(end) + 1] 
+0

Principali problemi con questo: 1) Uso di 'xrange' invece di' range'. 'xrange' non ha più alcun vantaggio su' range', dato che 'range' è un generatore e non pre-genera la lista dei risultati. Quindi 'xrange' è deprecato, e IIRC, nemmeno in Python 3. 2) Costruendo' endvalues' da 'values' quando potreste aver appena usato' list.index() 'e un'operazione slice.3) Questo non è il modo in cui contrassegni le domande come risposta su SO. –

+2

@Mike, 'xrange' è ancora richiesto in Python 2.7, che è stato rilasciato meno di 2 settimane fa. 'range' restituisce ancora una lista. –

+0

Ho aggiornato questo per usare slice e index(). Rimosso anche il testo a capo. –

4

Un suggerimento puramente basato su iteratori:

versione
import string 
import itertools 

def string_range(letters=string.ascii_lowercase, start="a", end="z"): 
    return itertools.takewhile(end.__ne__, itertools.dropwhile(start.__ne__, (x for i in itertools.count(1) for x in itertools.imap("".join, itertools.product(letters, repeat=i))))) 

print list(string_range(end="azc")) 
1

Ecco un modo migliore per farlo, se hai bisogno di una funzione di conversione:

for i in xrange(int('a', 36), int('azd', 36)): 
    if base36encode(i).isalpha(): 
     print base36encode(i, lower=True) 

Ed ecco la vostra funzione (grazie Wikipedia):

def base36encode(number, alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ', lower=False): 
    ''' 
    Convert positive integer to a base36 string. 
    ''' 
    if lower: 
     alphabet = alphabet.lower() 
    if not isinstance(number, (int, long)): 
     raise TypeError('number must be an integer') 
    if number < 0: 
     raise ValueError('number must be positive') 

    # Special case for small numbers 
    if number < 36: 
     return alphabet[number] 

    base36 = '' 
    while number != 0: 
     number, i = divmod(number, 36) 
     base36 = alphabet[i] + base36 

    return base36 

Ho virato sull'opzione di conversione in minuscolo, nel caso lo volessi.

1

ho generalizzato la risposta accettata per essere in grado di iniziare metà e per uso diverso da quello in minuscolo:

from string import ascii_lowercase, ascii_uppercase 
from itertools import product 

def letter_range(first, last, letters=ascii_lowercase): 
    for k in range(len(first), len(last)): 
     for x in product(letters, repeat=k+1): 
      result = ''.join(x) 
      if len(x) != len(first) or result >= first: 
       yield result 
       if result == last: 
        return 
print list(letter_range('a', 'zzz')) 
print list(letter_range('BA', 'DZA', ascii_uppercase)) 
Problemi correlati