10

Is there a way to do a letter range in python like this:

for x in range(a,h,)
derpyherp
  • 455
  • 4
  • 9
  • 18
  • 2
    possible dup of http://stackoverflow.com/questions/7001144/range-over-character-in-python and http://stackoverflow.com/questions/3190122/python-how-to-print-range-a-z (each of which have lots of good answers) – fantabolous Feb 05 '15 at 08:37
  • Does this answer your question? [range over character in python](https://stackoverflow.com/questions/7001144/range-over-character-in-python) – Dour High Arch Jun 14 '21 at 17:29

9 Answers9

22

Something like:

[chr(i) for i in range(ord('a'),ord('h'))]

Will give a list of alphabetical characters to iterate through, which you can then use in a loop

for x in [chr(i) for i in range(ord('a'),ord('h'))]:
    print(x)

or this will do the same:

for x in map(chr, range(*map(ord,['a', 'h']))):
    print(x)
Hansang
  • 1,494
  • 16
  • 31
Emanuele Paolini
  • 9,912
  • 3
  • 38
  • 64
  • 6
    Note that this doesn't include the last letter, so if you wanted to do the whole alphabet you'd do something like: [chr(i) for i in range(ord('a'),ord('z') + 1] – seddonym May 22 '13 at 14:17
5

You can use ord() to convert the letters into character ordinals and back:

def char_range(start, end, step=1):
    for char in range(ord(start), ord(end), step):
        yield chr(char)

It seems to work just fine:

>>> ''.join(char_range('a', 'z'))
    'abcdefghijklmnopqrstuvwxy'
Blender
  • 289,723
  • 53
  • 439
  • 496
3

There is no built in letter range, but you can write one:

def letter_range(start, stop):
    for c in xrange(ord(start), ord(stop)):
        yield chr(c)


for x in letter_range('a', 'h'):
    print x,

prints:

a b c d e f g
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
3

Emanuele's solution is great as long as one is only asking for a range of single characters, which I will admit is what the original questioner posed. There are also solutions out there to generate all multi-character combinations: How to generate a range of strings from aa... to zz. However I suspect that someone who wants a character like range function might want to be able to deal with generating an arbitrary range from say 'y' to 'af' (rolling over from 'z' to 'aa'). So here is a more general solution that includes the ability to either specify the last member of the range or its length.

def strange(start, end_or_len, sequence='ABCDEFGHIJKLMNOPQRSTUVWXYZ'):
    """Create a generator of a range of 'sequential' strings from
    start to end_or_len if end_or_len is a string or containing
    end_or_len entries if end_or_len is an integer.

    >>> list(strange('D', 'F'))
    ['D', 'E', 'F']
    >>> list(strange('Y', 'AB'))
    ['Y', 'Z', 'AA', 'AB']
    >>> list(strange('Y', 4))
    ['Y', 'Z', 'AA', 'AB']
    >>> list(strange('A', 'BAA', sequence='AB'))
    ['A', 'B', 'AA', 'AB', 'BA', 'BB', 'AAA', 'AAB', 'ABA', 'ABB', 'BAA']
    >>> list(strange('A', 11, sequence='AB'))
    ['A', 'B', 'AA', 'AB', 'BA', 'BB', 'AAA', 'AAB', 'ABA', 'ABB', 'BAA']
    """
    seq_len = len(sequence)
    start_int_list = [sequence.find(c) for c in start]
    if isinstance(end_or_len, int):
        inclusive = True
        end_int_list = list(start_int_list)
        i = len(end_int_list) - 1
        end_int_list[i] += end_or_len - 1
        while end_int_list[i] >= seq_len:
            j = end_int_list[i] // seq_len
            end_int_list[i] = end_int_list[i] % seq_len
            if i == 0:
                end_int_list.insert(0, j-1)
            else:
                i -= 1
                end_int_list[i] += j
    else:
        end_int_list = [sequence.find(c) for c in end_or_len]
    while len(start_int_list) < len(end_int_list) or start_int_list <= end_int_list:
        yield ''.join([sequence[i] for i in start_int_list])
        i = len(start_int_list)-1
        start_int_list[i] += 1
        while start_int_list[i] >= seq_len:
            start_int_list[i] = 0
            if i == 0:
                start_int_list.insert(0,0)
            else:
                i -= 1
                start_int_list[i] += 1


if __name__ =='__main__':
    import doctest
    doctest.testmod()
Malcolm
  • 461
  • 2
  • 10
2
import string

def letter_range(f,l,al = string.ascii_lowercase):
    for x in al[al.index(f):al.index(l)]:
        yield x

print ' '.join(letter_range('a','h'))

result

a b c d e f g
eyquem
  • 26,771
  • 7
  • 38
  • 46
1

this is easier for me at least to read/understand (and you can easily customize which letters are included, and in what order):

letters = 'abcdefghijklmnopqrstuvwxyz'
for each in letters:
    print each

result:
a
b
c
...
z
user3288829
  • 1,266
  • 15
  • 26
Joey
  • 11
  • 1
0

how about slicing an already pre-arranged list?

import string

s = string.ascii_lowercase
print( s[ s.index('b'):s.index('o')+1 ] )
jjisnow
  • 1,418
  • 14
  • 5
0

Malcom's example works great, but there is a little problem due to how Pythons list comparison works. If 'A' to "Z" or some character to "ZZ" or "ZZZ" will cause incorrect iteration.

Here "AA" < "Z" or "AAA" < "ZZ" will become false.

In Python [0,0,0] is smaller than [1,1] when compared with "<" or ">" operator.

So below line

while len(start_int_list) < len(end_int_list) or start_int_list <= end_int_list:

should be rewritten as below

while len(start_int_list) < len(end_int_list) or\
        ( len(start_int_list) == len(end_int_list) and start_int_list <= end_int_list):

It is well explained here https://docs.python.org/3/tutorial/datastructures.html#comparing-sequences-and-other-types

I rewrote the code example below.

def strange(start, end_or_len, sequence='ABCDEFGHIJKLMNOPQRSTUVWXYZ'):

    seq_len = len(sequence)
    start_int_list = [sequence.find(c) for c in start]
    if isinstance(end_or_len, int):
        inclusive = True
        end_int_list = list(start_int_list)
        i = len(end_int_list) - 1
        end_int_list[i] += end_or_len - 1
        while end_int_list[i] >= seq_len:
            j = end_int_list[i] // seq_len
            end_int_list[i] = end_int_list[i] % seq_len
            if i == 0:
                end_int_list.insert(0, j-1)
            else:
                i -= 1
                end_int_list[i] += j
    else:
        end_int_list = [sequence.find(c) for c in end_or_len]

    while len(start_int_list) < len(end_int_list) or\
         (len(start_int_list) == len(end_int_list) and start_int_list <= end_int_list):**
        yield ''.join([sequence[i] for i in start_int_list])
        i = len(start_int_list)-1
        start_int_list[i] += 1
        while start_int_list[i] >= seq_len:
            start_int_list[i] = 0
            if i == 0:
                start_int_list.insert(0,0)
            else:
               i -= 1
                start_int_list[i] += 1

Anyway, Malcom's code example is a great illustration of how iterator in Python works.

Kay
  • 1,235
  • 2
  • 13
  • 27
0

Sometimes one can over-design what can be a simple solution. If you know the range of letters you want, why not just use:

for letter in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
    print(letter)

Or even:

start = 4
end = 9
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for letter in alphabet[start:end]:
    print(letter)

In the second example I illustrate an easy way to pick how many letters you want from a fixed list.

  • This only half answers the question, but does provide an interesting simpler approach that could be useful in some situations. – joanis Jun 14 '21 at 19:21