print a ... z, A ... Z, "\n"' in Python

J

js

HI guys,

How do you write Perl's

print a ... z, A ... Z, "\n"' in Python


In Python?


A way I came up with is the following, but I'm sure this is ugly.

''.join(chr(c) for c in (range(ord('a'), ord('z')+1) +
range(ord('A'), ord('Z')+1)))
or
crange = lambda c1, c2: [ chr(c) for c in range(ord(c1), ord(c2)+1) ]
''.join(chr(c) for c in crange('a', 'z') + crange('A', 'Z'))


I want to feel The Zen of Python :)
 
B

bearophileHUGS

js:
crange = lambda c1, c2: [ chr(c) for c in range(ord(c1), ord(c2)+1) ]
''.join(chr(c) for c in crange('a', 'z') + crange('A', 'Z'))

Yes, managing char ranges is a bit of pain with Python.
You can also pack those chars:

xcrange = lambda cc: (chr(c) for c in xrange(ord(cc[0]), ord(cc[1])
+1))

But I don't like that much.

The calls:
''.join(xcrange('az')) + ''.join(xcrange('AZ'))

But note that you return the last item of the range too, and that goes
against the semantic of the usual Python range/xrange, so you may want
to call this function with another name.

Maybe there are better ways to solve this problem. Maybe a way to
generate (closed?) char ranges can be added to the Python standard
lib.

Bye,
bearophile
 
J

js

But note that you return the last item of the range too, and that goes
against the semantic of the usual Python range/xrange, so you may want
to call this function with another name.

That makes sense. 100% agree with you.
Maybe there are better ways to solve this problem. Maybe a way to
generate (closed?) char ranges can be added to the Python standard
lib.

Maybe we don't want char range If string constants would be rich enough.
 
M

MonkeeSage

js said:
A way I came up with is the following, but I'm sure this is ugly.

You could abuse __getitem__ (terribly, heh!) and use slice syntax...

class crange():
def __init__(self):
self.valid = range(47,58) + range(65,91) + range(97,123)
def __getitem__(self, s):
if isinstance(s, slice):
start, stop = s.start, s.stop
if not start: start = '0'
if isinstance(stop, int) and stop > 122: stop = 'z'
elif not stop: stop = 'z'
clist = []
chars = range(ord(start), ord(stop)+1)
for i in range(len(chars)):
if chars in self.valid:
clist.append(chr(chars))
return ''.join(clist)
else:
return s

cr = crange()
print cr['A':'z']
print cr['0':'8']
print cr[:]

Regards,
Jordan
 
L

Lloyd Zusman

js said:
That makes sense. 100% agree with you.


Maybe we don't want char range If string constants would be rich
enough.

But as soon as we want a string that doesn't correspond to any
pre-defined constants, we're hosed. For example, there isn't
a constant that would correspond to this Perl-ism:

print l ... w, e ... j, L ... W, E ... J, "\n";
 
J

js

Maybe we don't want char range If string constants would be rich
But as soon as we want a string that doesn't correspond to any
pre-defined constants, we're hosed. For example, there isn't
a constant that would correspond to this Perl-ism:

print l ... w, e ... j, L ... W, E ... J, "\n";

Yes, I'm certain that l ... w, e ..j will never be a constant
because that doesn't mean a thing so nobody want them :)
 
A

Alex Martelli

js said:
HI guys,

How do you write Perl's

print a ... z, A ... Z, "\n"' in Python

In Python?

This specific one is easy, though this doesn't generalize:

import string
print string.lowercase + string.uppercase

For the general case, there's no way to avoid calling chr and ord,
because a string in Python doesn't have a "natural successor". So the
only issue is how you prefer to hide those calls &c (in some class or
function) and you already received suggestions on that.


Alex
 
R

rzed

(e-mail address removed) (Alex Martelli) wrote in

This specific one is easy, though this doesn't generalize:

import string
print string.lowercase + string.uppercase

For the general case, there's no way to avoid calling chr and
ord, because a string in Python doesn't have a "natural
successor". So the only issue is how you prefer to hide those
calls &c (in some class or function) and you already received
suggestions on that.

No ord or chr in sight:

# Inclusive character range.
def pycrange(lo,hi):
import string
chars = string.letters + " "
rstr = ''
lp = chars.find(lo)
hp = chars.find(hi)
if lp < hp:
rstr = chars[lp:hp+1]
return rstr

print pycrange('c','n')


Lame code, though.
 
A

Alex Martelli

rzed said:
(e-mail address removed) (Alex Martelli) wrote in

This specific one is easy, though this doesn't generalize:

import string
print string.lowercase + string.uppercase

For the general case, there's no way to avoid calling chr and
ord, because a string in Python doesn't have a "natural
successor". So the only issue is how you prefer to hide those
calls &c (in some class or function) and you already received
suggestions on that.

No ord or chr in sight:

# Inclusive character range.
def pycrange(lo,hi):
import string
chars = string.letters + " "
rstr = ''
lp = chars.find(lo)
hp = chars.find(hi)
if lp < hp:
rstr = chars[lp:hp+1]
return rstr

print pycrange('c','n')


Lame code, though.

Very (the very existence of rstr and the if block are redundant, for
example; "return chars[lp:hp+1]" will already return an empty string
when lp > hp, and it's weird for the result to be empty for equal
arguments lo and hi when it's a length-two string for arguments, say,
'a' and 'b').

Also incorrect, presumably, since it would e.g. consider pycrange('w',
'C') to be 'wxyzABC', rather than empty (as an ord/chr based solution
would) or 'wxyz' (as I believe Perl does for 'w'...'C' -- one of those
black-magical Perl things, unless they've changed it recently) -- in
ASCII, uppercase letters come before lowercase ones, but in
string.letters they're vice versa.

Sure, you can get a complete 256-char ASCII alphabet with
alp=string.maketrans('', ''), use alp.find(x) as roughly equivalent to
ord(x) and alp[y] as roughly equivalent to chr(y), and thus (or by
sillier tricks yet) you wouldn't _formally_ "be calling chr and ord"
(you'd instead use roughly equivalent but slower and murkier idioms).
However, my point was: you can't avoid transforming from characters to
numbers and back again (ord and chr are just the "one obvious way" to do
that -- correct, if you want ASCII, readable, direct, and fast). .find
and indexing (instead of ord and chr) do give you more flexibility (to
use an underlying order that's not ASCII's) should you need that; and
slicing an appropriate string does avoid an explicit loop.

(Just trying to forestall further silliness...): other ways to avoid
"calling chr and ord" include abusing modules struct and array.


Alex
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,111
Latest member
VetaMcRae
Top