473,386 Members | 1,841 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Incrementing a string

I've used perl for a lot of 'throw away' scripts; I like Python better in
principle, from reading about it, but it was always easier to just use
perl rather than learn python.

Now I'm writing a smallish program that I expect to keep around, so am
taking this opportunity to try to learn some Python. I have a need for
computer generated set of simple string lables. I don't know how many in
advance---each is produced as a result of a user action.

In perl I simply initiated

$label= "a";

Then, after using it doing

$label++;

This conveniently steps through the alphabet, then goes on to aa, ab,ac,
....

In Python I can get from a to z with a generator as so:
def gen_alph(): .... for i in range(97,123):
.... yield chr(i)
.... g = gen_alph()
g.next() 'a' g.next() 'b' g.next()

'c'

But it looks like going beyond z to aa and so on is (relatively) complicated.

In truth, it seems unlikely that I would ever go beyond z in using my
application, and certainly not beyond zz which wouldn't be too hard to
program. But I hate to build in limitations no matter how reasonable.

It seems like there should be a better way that I'm missing because I'm
thinking in perl, not thinking in Python. :-)

Best,

John Velman
Jul 18 '05 #1
11 4712
John Velman <ve****@cox.net> writes:
But it looks like going beyond z to aa and so on is (relatively)
complicated.

In truth, it seems unlikely that I would ever go beyond z in using my
application, and certainly not beyond zz which wouldn't be too hard to
program. But I hate to build in limitations no matter how reasonable.


Python doesn't have that feature built in, so you have to think about
how Perl really does it, and implement something similar in Python.
Yes, it will be a little bit complicated, but the Perl implementers
had to deal with the same complexity, and it's a decent exercise for
you to do the same.
Jul 18 '05 #2
[John Velman]:

[how do I implement "$a = 'z'; $a++;" in Python?]


is there any reason you need your labels to be on this format?
usually, I would find a plain "L42" more readable.

def gen_label():
num = 0
while True:
num += 1
yield "L" + str(num)
Perl's increment operator isn't a generator, it just changes the
current value so you can jump back and forth. here's one quick go at
it. I'm sure it can be done more prettily, and probably without
assuming the string is ASCII :-)

def incr(s):
i = 1
while i <= len(s):
if 'a' <= s[-i] < 'z':
return s[:-i] + chr(88 + int(s[-i], 36)) + s[len(s)+1-i:]
elif s[-i] == 'z':
s = s[:-i] + 'a' + s[len(s)+1-i:]
else:
raise ValueError
i += 1
return 'a' + s

--
Kjetil T.
Jul 18 '05 #3
#### begin sample program ####

import string

class LabelCounter(object):
digits = string.lowercase

def __init__(self, value=0):
self.value = value

def __str__(self):
letters = []
i = self.value
while i:
d, m = divmod(i, len(self.digits))
letters.append(self.digits[m])
i = d
return ''.join(letters[::-1]) or self.digits[0]

def __add__(self, other):
return LabelCounter(self.value + other)

def __lt__(self, other):
return self.value < other

# define other operators as needed; it's a shame this can't inherit from
# int and get these for free. It can't do this because all of int's
# operators return ints, not LabelCounters.
i = LabelCounter(0)
while i < 50:
print i
i += 1

#### end sample program ####

You can set 'digits' to any sequence at all. Set it to '01' to get
output in binary, or to ['01','23','45','67','89'] to get base 5 in a
very confusing notation *g*

On Wed, Sep 15, 2004 at 03:08:20PM -0700, John Velman wrote:
I've used perl for a lot of 'throw away' scripts; I like Python better in
principle, from reading about it, but it was always easier to just use
perl rather than learn python.

Now I'm writing a smallish program that I expect to keep around, so am
taking this opportunity to try to learn some Python. I have a need for
computer generated set of simple string lables. I don't know how many in
advance---each is produced as a result of a user action.

In perl I simply initiated

$label= "a";

Then, after using it doing

$label++;

This conveniently steps through the alphabet, then goes on to aa, ab,ac,
...

In Python I can get from a to z with a generator as so:
def gen_alph(): ... for i in range(97,123):
... yield chr(i)
... g = gen_alph()
g.next() 'a' g.next() 'b' g.next()

'c'

But it looks like going beyond z to aa and so on is (relatively) complicated.

In truth, it seems unlikely that I would ever go beyond z in using my
application, and certainly not beyond zz which wouldn't be too hard to
program. But I hate to build in limitations no matter how reasonable.

It seems like there should be a better way that I'm missing because I'm
thinking in perl, not thinking in Python. :-)

Best,

John Velman
--
http://mail.python.org/mailman/listinfo/python-list

Jul 18 '05 #4
John Velman wrote:
$label++;

This conveniently steps through the alphabet, then goes on to aa, ab,ac,
...

In Python I can get from a to z with a generator as so: [snip] But it looks like going beyond z to aa and so on is (relatively)
complicated.


Here's one way, perhaps it is simple enough for you:

import string

def strpp(s):
for i in s:
yield i
for i in strpp(s):
for j in s:
yield i + j

labels = strpp(string.lowercase)
label = label.next() # ad infinitum
Hope you enjoy Python,
Jeffrey
Jul 18 '05 #5
On Wed, 15 Sep 2004 15:08:20 -0700 John wrote:
This conveniently steps through the alphabet, then goes on to aa, ab,ac,


Puzzling... I hacked at this problem as a flexibility learning exercise
and actually got this to work; but... does 'while True' in a generator
have side-effects...?? Or generator recursion?

Maybe I'm just tired -- I don't see how the string actually _grows_ inside
the while.... :^?

I was just expecting the prefix to be '', then 'a'...'z' giving a..z,
aa..az, ba..bz, ... za..zz -- not continuing through aaa...azz and
onwards... It's cool; but boggles my mind at the moment... not that
that's a stretch... :^)

def ascinc(start='a',end='z'):
g = ascinc(start,end)
prefix = ''
while True:
for i in range(ord(start[-1]),ord(end[-1])+1):
yield (prefix + chr(i))
prefix = g.next()
print "what you wanted..."
g = ascinc('a')

for i in range(100):
print g.next(),

print
print "including some flexibility..."

g = ascinc('0','1')

for i in range(100):
print g.next(),
Jul 18 '05 #6
Here's my generator version:

def gen_alph():
def convert(k,n):
# convert integer k to n-letter string
out = []
for i in xrange(n):
k,r = divmod(k,26)
out.append(chr(97+r))
out.reverse()
return ''.join(out)

nletters = 1
while True:
for k in xrange(26**nletters):
yield convert(k, nletters)
nletters += 1

To test it:

g = gen_alph()
for i in range(40):
print i, g.next()
Jul 18 '05 #7
Phil Frost wrote:
import string

class LabelCounter(object):
digits = string.lowercase .... # define other operators as needed; it's a shame this can't inherit from
# int and get these for free. It can't do this because all of int's
# operators return ints, not LabelCounters.
Try this instead. As usual with clever solutions, you
probably shouldn't use this in real code.

import string

def fixup(klass):
for name, meth in inspect.getmembers(klass):
# Find all the methods except for a few special ones
# we know won't return integers
if (callable(meth) and name not in
["__class__", "__new__", "__init__", "__str__", "__repr__"]):

# Need to make a wrapper function (g) for each of these methods.
# The wrapper function needs to know the original method, which
# is stored in the newly created scope (f).
def f(meth = meth):
def g(self, *args, **kwargs):
retval = meth(self, *args, **kwargs)
if isinstance(retval, int):
return LabelCounter(retval)
return retval
return g
g = f()
setattr(klass, name, g) # replace with the wrapped version

class LabelCounter(int):
digits = string.ascii_lowercase
def __str__(self):
letters = []
i = int(self)
while i:
d, m = divmod(i, len(self.digits))
letters.append(self.digits[m])
i = d
return "".join(letters[::-1]) or self.digits[0]
__repr__ = __str__
Here it is in use.
a = LabelCounter(4)
print a e print a+1 f print a+10 o print (a+10)/2 h print a e print a/2 c print a/3 b print a/30 a print a**4 jw You can set 'digits' to any sequence at all. Set it to '01' to get
output in binary, or to ['01','23','45','67','89'] to get base 5 in a
very confusing notation *g*


I set it to ascii_lowercase since string.lowercase is locale
dependent.
import string, locale
string.lowercase 'abcdefghijklmnopqrstuvwxyz' locale.setlocale(locale.LC_ALL, "de_DE") 'de_DE' string.lowercase 'abcdefghijklmnopqrstuvwxyz\xaa\xb5\xba\xdf\xe0\xe 1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\ xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xf b\xfc\xfd\xfe\xff'


OTOH, that might be what you wanted ...

Andrew
da***@dalkescientific.com
Jul 18 '05 #8
Jeffrey Froman wrote:
import string

def strpp(s):
for i in s:
yield i
for i in strpp(s):
for j in s:
yield i + j

labels = strpp(string.lowercase)
label = label.next() # ad infinitum


string.ascii_lowercase may be preferable here.
Jul 18 '05 #9
Thanks to everyone who responded! I've learned a good deal by reading
through the solutions. Don't know which one I'll use yet (or perhaps I'll
use something suggested by them), but these take me another step toward
'thinking in Python'. Also, I might add, it's really hard to know of all
the machinery that is available --- there is so much of it. I now know
about the itertools module, for example.

Kjetil Torgrim Homme asked why not just make the labels L1, L2, ..., Paul
Foley proposed similarly: label1, label2, ..., and also suggested that if
$label="one" it would make sense for $label++ to be "two".

Either of these would work (although "one","two",... would be yet a
different programming problem). I prefer my initial choice because the
labels will be used interactively, and I prefer to be able to do
everything from the keyboard. It's easier for me to type "aq" than "L42".
I'm a pretty good touch typist as far as lower case letters go, but
usually have to look at the keyboard to type numerals. So "m" is
preferable to "L12" but, to me, there isn't much difference between
typing "l12" and "label12".

I think some of the proposed solutions would make it easy to taylor the
kind of label as a user preference if I ever get this application to the
point that I think someone else might be interested in using it.

And yes, I think I'm going to enjoy Python.

Best,

John Velman
Jul 18 '05 #10

"Pierre Fortin" <pf*****@pfortin.com> wrote in message
news:20*********************@gypsy.pfortin.com...
On Wed, 15 Sep 2004 15:08:20 -0700 John wrote:
Puzzling... I hacked at this problem as a flexibility learning exercise
and actually got this to work; but... does 'while True' in a generator
have side-effects...??
No. Note that the 'while True' and the rest of the body code end up in/as
the body of the .next method of the generator object produced by calling
the generator function. You don't have to understand all this to use
generators in for statements, but you should when using them with while
loops.
Or generator recursion?
I has a main of sometimes simplifying variable depth recursion ;-)
I don't see how the string actually _grows_ inside the while.... :^?
I was just expecting the prefix to be '', then 'a'...'z' giving a..z,
aa..az, ba..bz, ... za..zz -- not continuing through aaa...azz and
onwards... It's cool; but boggles my mind at the moment... not that
that's a stretch... :^)
The following is an never-ending generator, with unbounded levels of
recursion. The generator on each level of recursion is the same and
therefore generates the same sequence. Each is 'behind' the level above it
and 'ahead' of the level beneath (counting the first as the top level) in
terms of where it is in the sequence.

Prefix grows from length 0 to 1 on the first call to the next method of the
level beneath it. That same call causes the creation of another 'instance'
(still inactive) two levels down. When a later g.next call causes the
prefix one level down to grow from 0 to 1, the prefix as the current level
grows from 1 to 2. And so on. At any time (except transitions), there is
a stack of n+1 identical instances of the generator (and its .next methods)
with prefixes ranging from length n-1 down to 0 with the bottom instance
having no prefix at all.
def ascinc(start='a',end='z'):
g = ascinc(start,end)
This creates a new generator object but does NOT call its .next method.
prefix = ''
while True:
for i in range(ord(start[-1]),ord(end[-1])+1):
yield (prefix + chr(i))
prefix = g.next()
Increments in prefix length bubble up from the bott
g = ascinc('a')
This 'kickstarts' the process by creating the top generator without calling
it.
for i in range(100):
print g.next(),


while True: print g.next() # would theorectically continue indefinitely, as
would
for s in ascinc('a'): print s # both would croak on the recursion limit

In each case, the first call of .next() causes creation of a second
generator and a blank prefix. I hope the mechanism is now clearer for you.

Terry J. Reedy

Jul 18 '05 #11
On Thu, 16 Sep 2004 21:13:50 -0400 Terry wrote:
I hope the mechanism is now clearer for you.


Yes, thank you... I was getting pretty sleepy at the time and I thought
this was likely -- obviously since I coded it... :^) I was wanting the
effect I finally got, just was unclear how it was actually occurring....

One more notch on the road to expert level... :>

-30-

BTW, someone wondered about "-30-"...

From journalism handbooks:
At the end of a story, write "End" or "30" -- a journalism symbol
for "finish".

I use it when I'm pretty sure I'm done with a thread...

Regards,
Pierre
Jul 18 '05 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
by: Michael | last post by:
Hi, I've got a string s, and i want to shift all the letters up by one, eg a->b, b->c ........ z->a In c++ i can do this quite simply with if(C == 'z') C='a'; else C++; but i can't work out...
3
by: James Aguilar | last post by:
Hey all, I have a bit of code that implements a suffix array, which is essentially an array of iterators or indexes into a string. The array starts out like this String: ABAB Array: 0123 ...
2
by: brian | last post by:
Hi, before coming to .NET, I utilized regular expressions mostly in JScript / JavaScript and also in my favorite text editor: TextPad (www.textpad.com) I don't know about JScript/JavaScript, but...
8
by: mantrid | last post by:
Hello I have the following code, where clicking yh1r is supposed to move h1 10px down and update the value of yh1 by 20 each time its clicked. what the code actually does is NOT move h1 and...
1
by: snareklutz | last post by:
Hi, I saw the thread here: http://www.thescripts.com/forum/thread255915.html and I am currently working on building on it. Well, what I need is something that takes in a string and increments...
4
by: masterpaladin38 | last post by:
I've been working on this problem for some time and I must say I'm stump. Any help would be appreciated. Basically what I'm trying to do is write the results of a loop to a new text file with...
7
by: jwhitby3 | last post by:
Hi all, I am trying to develop what amounts to a data entry page for the company I work for, (mostly to make my job easier). I think that I am beginning to grasp php, but I am at a loss now. I...
1
by: jesmi | last post by:
hi i got problem in inserting the date into the database. my requirement is that when i choose a date ie from :2007-01-01 & to :2007-12-01 then all the dates starting from 2007-02-01 upto...
3
by: =?Utf-8?B?TWlrZSBL?= | last post by:
I have a Net 2.0 app in VB that has code like this: Dim intA as Integer Dim intB as Integer dim myList as new List(Of String) intA = 10 intB = 20 .... code to fill the list ....
9
by: subramanian100in | last post by:
The following portion is from c-faq.com - comp.lang.c FAQ list · Question 6.13 int a1 = {0, 1, 2}; int a2 = {{3, 4, 5}, {6, 7, 8}}; int *ip; /* pointer to int */ int (*ap); /* pointer to...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.