106

Is there a way to range over characters? Something like this:

for c in xrange( 'a', 'z' ):
    print c
1
  • 19
    If you just want the English alphabet, there's import string, string.ascii_lowercase. Commented Aug 9, 2011 at 18:44

16 Answers 16

140

This is a great use for a custom generator:

Python 3:

def char_range(c1, c2):
    """Generates the characters from `c1` to `c2`, inclusive."""
    for c in range(ord(c1), ord(c2)+1):
        yield chr(c)

then:

for c in char_range('a', 'z'):
    print(c)

Python 2:

def char_range(c1, c2):
    """Generates the characters from `c1` to `c2`, inclusive."""
    for c in xrange(ord(c1), ord(c2)+1):
        yield chr(c)

then:

for c in char_range('a', 'z'):
    print c
Sign up to request clarification or add additional context in comments.

6 Comments

Beautiful! For anyone who's going to copy this, keep in mind that range(1,3) iterates values 1 and 2 (and not three), but char_range('a','c') will iterate 'a', 'b' and 'c'!
You could add the optional step arg too: def char_range(c1, c2, step=1) ... ord(c1), ord(c2)+1, step
@wjandrea, doesn't quite work for negative steps, eg char_range('g','a',-1) gives ['g', 'f', 'e', 'd', 'c']
@alan Nice catch! Looks like that's the fault of the +1 on ord(c2). So replace ord(c2)+1 with ord(c2) + (1 if step > 0 else -1). Though for clarity's sake you might want to factor that out of the range() call.
The problem with doing that, is that to generate a-z, you will need to know which character comes after z. Not especially comfortable. Probably better to avoid the name «range» (use closedrange or inclusiverange instead ?)
|
111
import string
for char in string.ascii_lowercase:
    print char

See string constants for the other possibilities, including uppercase, numbers, locale-dependent characters, all of which you can join together like string.ascii_uppercase + string.ascii_lowercase if you want all of the characters in multiple sets.

Comments

27

You have to convert the characters to numbers and back again.

for c in xrange(ord('a'), ord('z')+1):
    print chr(c) # resp. print unicode(c)

For the sake of beauty and readability, you can wrap this in a generator:

def character_range(a, b, inclusive=False):
    back = chr
    if isinstance(a,unicode) or isinstance(b,unicode):
        back = unicode
    for c in xrange(ord(a), ord(b) + int(bool(inclusive)))
        yield back(c)

for c in character_range('a', 'z', inclusive=True):
    print(chr(c))

This generator can be called with inclusive=False (default) to imitate Python's usual bhehaviour to exclude the end element, or with inclusive=True (default) to include it. So with the default inclusive=False, 'a', 'z' would just span the range from a to y, excluding z.

If any of a, b are unicode, it returns the result in unicode, otherwise it uses chr.

It currently (probably) only works in Py2.

3 Comments

You can hide this in a generator: see my answer.
You mean you like it better with the ord's and chr's in your face? And if you had to do this more than once you'd duplicate it in each place? Odd..
so I had better said 'that looks better' than 'this looks better'.
13

If you have a short fixed list of characters, just use Python's treatment of strings as lists.

for x in 'abcd':
    print x

or

[x for x in 'abcd']

Comments

12

There are other good answers here (personally I'd probably use string.lowercase), but for the sake of completeness, you could use map() and chr() on the lower case ascii values:

for c in map(chr, xrange(97, 123)):
   print c

Comments

10

I like an approach which looks like this:

base64chars = list(chars('AZ', 'az', '09', '++', '//'))

It certainly can be implemented with a lot of more comfort, but it is quick and easy and very readable.

Python 3

Generator version:

def chars(*args):
    for a in args:
        for i in range(ord(a[0]), ord(a[1])+1):
            yield chr(i)

Or, if you like list comprehensions:

def chars(*args):
    return [chr(i) for a in args for i in range(ord(a[0]), ord(a[1])+1)]

The first yields:

print(chars('ĀĈ'))
<generator object chars at 0x7efcb4e72308>
print(list(chars('ĀĈ')))
['Ā', 'ā', 'Ă', 'ă', 'Ą', 'ą', 'Ć', 'ć', 'Ĉ']

while the second yields:

print(chars('ĀĈ'))
['Ā', 'ā', 'Ă', 'ă', 'Ą', 'ą', 'Ć', 'ć', 'Ĉ']

It is really convenient:

base64chars = list(chars('AZ', 'az', '09', '++', '//'))
for a in base64chars:
   print(repr(a),end='')
print('')
for a in base64chars:
   print(repr(a),end=' ')

outputs

'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''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''0''1''2''3''4''5''6''7''8''9''+''/'
'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' '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' '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' '+' '/' 

Why the list()? Without base64chars might become a generator (depending on the implementation you chose) and thus can only be used in the very first loop.

Python 2

Similar can be archived with Python 2. But it is far more complex if you want to support Unicode, too. To encourage you to stop using Python 2 in favor of Python 3 I do not bother to provide a Python 2 solution here ;)

Try to avoid Python 2 today for new projects. Also try to port old projects to Python 3 first before extending them - in the long run it will be worth the effort!

Proper handling of Unicode in Python 2 is extremely complex, and it is nearly impossible to add Unicode support to Python 2 projects if this support was not build in from the beginning.

Hints how to backport this to Python 2:

  • Use xrange instead of range
  • Create a 2nd function (unicodes?) for handling of Unicode:
    • Use unichr instead of chr to return unicode instead of str
    • Never forget to feed unicode strings as args to make ord and array subscript work properly

Comments

7

For Uppercase Letters:

for i in range(ord('A'), ord('Z')+1):
    print(chr(i))

For Lowercase letters:

for i in range(ord('a'), ord('z')+1):
    print(chr(i))

1 Comment

When printing only Range Value that will return only Unicode values of characters, After typecasting to chr() that will return the proper character
5
for character in map(   chr, xrange( ord('a'), ord('c')+1 )   ):
   print character

prints:

a
b
c

Comments

5
# generating 'a to z' small_chars.
small_chars = [chr(item) for item in range(ord('a'), ord('z')+1)]
# generating 'A to Z' upper chars.
upper_chars = [chr(item).upper() for item in range(ord('a'), ord('z')+1)]

Comments

3

Inspired from the top post above, I came up with this :

map(chr,range(ord('a'),ord('z')+1))                     

Comments

2

Using @ned-batchelder's answer here, I'm amending it a bit for python3

def char_range(c1, c2):
    """Generates the characters from `c1` to `c2`, inclusive."""
    """Using range instead of xrange as xrange is deprecated in Python3""" 
    for c in range(ord(c1), ord(c2)+1):
        yield chr(c)

Then same thing as in Ned's answer:

for c in char_range('a', 'z'):
    print c

Thanks Ned!

Comments

1

i had the same need and i used this :

chars = string.ascii_lowercase
range = list(chars)[chars.find('a'):chars.find('k')+1]

Hope this will Help Someone

1 Comment

This is a good idea and was elegant for my application, something like: for c in string.ascii_uppercase (note: the OP has a range end "bug").
0

Use "for count in range" and chr&ord:

print [chr(ord('a')+i) for i in range(ord('z')-ord('a'))]

Comments

0

Use list comprehension:

for c in [chr(x) for x in range(ord('a'), ord('z'))]:
    print c

Comments

0

Another option (operates like range - add 1 to stop if you want stop to be inclusive)

>>> import string
>>> def crange(arg, *args):
...     """character range, crange(stop) or crange(start, stop[, step])"""
...     if len(args):
...         start = string.ascii_letters.index(arg)
...         stop = string.ascii_letters.index(args[0])
...     else:
...         start = string.ascii_letters.index('a')
...         stop = string.ascii_letters.index(arg)
...     step = 1 if len(args) < 2 else args[1]
...     for index in range(start, stop, step):
...         yield string.ascii_letters[index]
...
>>> [_ for _ in crange('d')]
['a', 'b', 'c']
>>>
>>> [_ for _ in crange('d', 'g')]
['d', 'e', 'f']
>>>
>>> [_ for _ in crange('d', 'v', 3)]
['d', 'g', 'j', 'm', 'p', 's']
>>>
>>> [_ for _ in crange('A', 'G')]
['A', 'B', 'C', 'D', 'E', 'F']

Comments

0

Depending on how complex the range of characters is, a regular expression may be convenient:

import re
import string

re.findall("[a-f]", string.printable)
# --> ['a', 'b', 'c', 'd', 'e', 'f']

re.findall("[n-qN-Q]", string.printable)
# --> ['n', 'o', 'p', 'q', 'N', 'O', 'P', 'Q']

This works around the pesky issue of accidentally including the punctuation characters in between numbers, uppercase and lowercase letters in the ASCII table.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.