views:

1714

answers:

4

In Python (specifically Python 3.0 but I don't think it matters), how do I easily write a loop over a sequence of characters having consecutive character codes? I want to do something like this pseudocode:

for Ch from 'a' to 'z' inclusive: #
    f(Ch)

Example: how about a nice "pythonic" version of the following?

def Pangram(Str):
    ''' Returns True if Str contains the whole alphabet, else False '''
    for Ch from 'a' to 'z' inclusive: #
        M[Ch] = False
    for J in range(len(Str)):
        Ch = lower(Str[J])
        if 'a' <= Ch <= 'z':
            M[Ch] = True
    return reduce(and, M['a'] to M['z'] inclusive) #

The lines marked # are pseudocode. Of course reduce() is real Python!

Dear wizards (specially old, gray-bearded wizards), perhaps you can tell that my favorite language used to be Pascal...

+18  A: 

You have a constant in the string module called ascii_lowercase, try that out:

>>> from string import ascii_lowercase

Then you can iterate over the characters in that string.

>>> for i in ascii_lowercase :
...     f(i)

For your pangram question, there is a very simple way to find out if a string contains all the letters of the alphabet. Using ascii_lowercase as before,

>>> def pangram(str) :
...     return set(ascii_lowercase).issubset(set(str))
sykora
I hope your beard's acceptable to the OP :)
llimllib
If I also get to be a wizard, I'll live with the beard :)
sykora
+5  A: 

Iterating a constant with all the characters you need is very Pythonic. However if you don't want to import anything and are only working in Unicode, use the built-ins ord() and its inverse chr().

for code in range(ord('a'), ord('z')):
     print chr(code)
Bluu
Unicode version of chr() is unichr()
Ryan Ginstrom
One more thing: if you want the range to be inclusive, do>>> for code in range(ord('a'), ord('z')+1): print unichr(code)
Ryan Ginstrom
do not advise against importing from the standard lib
hop
Exactly what I needed! The other solutions don't work for ranges of letters determined at runtime.
Paul
A: 

I would write a function similar to Python's range

def alpha_range(*args):
  if len(args) == 1:
    start, end, step = ord('a'), ord(args[0]), 1
  elif len(args) == 2:
    start, end, step = ord(args[0]), ord(args[1]), 1
  else:
    start, end, step = ord(args[0]), ord(args[1]), args[2]
  return (chr(i) for i in xrange(start, end, step))
Cristian
+6  A: 

You've got to leave the Pascal-isms behind and learn Python with a fresh perspective.

>>> ascii_lowercase
'abcdefghijklmnopqrstuvwxyz'
>>> def pangram( source ):
    return all(c in source for c in ascii_lowercase)

>>> pangram('hi mom')
False
>>> pangram(ascii_lowercase)
True

By limiting yourself to what Pascal offered, you're missing the things Python offers.

And... try to avoid reduce. It often leads to terrible performance problems.


Edit. Here's another formulation; this one implements set intersection.

>>> def pangram( source ):
>>>     notused= [ c for c in ascii_lowercase if c not in source ]
>>>     return len(notused) == 0

This one gives you a piece of diagnostic information for determining what letters are missing from a candidate pangram.

S.Lott
sorry, generator expressions are in 2.4 and up, not 2.3
hop
@hop: I don't get the comment. The code change looks fine, but the comment is opaque.
S.Lott
@s.lott: i wrote in the comment to the change itself that GEs work in 2.3+
hop
@hop: Got it -- you removed the list comprehension because it is no longer required.
S.Lott