5

I need a simple program that given a string, returns to me the next one in the alphanumeric ordering (or just the alphabetic ordering).

f("aaa")="aab"
f("aaZ")="aba"

And so on.

Is there a function for this in one of the modules already?

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
Pietro Speroni
  • 3,131
  • 11
  • 44
  • 55
  • 1
    Libraries typically expose functions because they are useful more so than because they are trivial. I would actually be surprised if there were library support for this exact function, because the specification is a bit arbitrary and I can't think of any general use cases for having such a function. – Joe Holloway May 31 '09 at 17:47
  • Well, the general case would take a string over an alphabet and the alphabet as a list. And then gives the successor. You think this is irrelevant? Well, there are all sort of algebras that are generated by a successor function and a primitive functions. Like the naturals, for example. – Pietro Speroni May 31 '09 at 20:08
  • I think the examples are not for the function that gives the next string in alphabetic order. In alphabetics order it should return f(aaa)=aaaa and f(aaZ)=aaZa. – Jaakko Seppälä Aug 23 '19 at 10:03

4 Answers4

12

I don't think there's a built-in function to do this. The following should work:

def next_string(s):
    strip_zs = s.rstrip('z')
    if strip_zs:
        return strip_zs[:-1] + chr(ord(strip_zs[-1]) + 1) + 'a' * (len(s) - len(strip_zs))
    else:
        return 'a' * (len(s) + 1)

Explanation: you find the last character which is not a z, increment it, and replace all of the characters after it with a's. If the entire string is z's, then return a string of all a's that is one longer.

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • Thanks. Works perfectly. (Actually to be precise, just in case someone uses this later on, this only goes through the lower case letter. But for me is ok. Cheers, Pietro – Pietro Speroni May 31 '09 at 20:03
  • Sucks there's no native python method for this: http://www.ruby-doc.org/core-1.9.3/String.html#method-i-succ – Grocery Sep 10 '12 at 17:09
3

Are the answers at How would you translate this from Perl to Python? sufficient? Not 100% what you're asking, but close...

Community
  • 1
  • 1
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
2

A different, longer, but perhaps more readable and flexible solution:

def toval(s):
    """Converts an 'azz' string into a number"""
    v = 0
    for c in s.lower():
        v = v * 26 + ord(c) - ord('a')
    return v

def tostr(v, minlen=0):
    """Converts a number into 'azz' string"""
    s = ''
    while v or len(s) < minlen:
        s = chr(ord('a') + v % 26) + s
        v /= 26
    return s

def next(s, minlen=0):
    return tostr(toval(s) + 1, minlen)

s = ""
for i in range(100):
    s = next(s, 5)
    print s

You convert the string into a number where each letter represents a digit in base 26, increase the number by one and convert the number back into the string. This way you can do arbitrary math on values represented as strings of letters.

The ''minlen'' parameter controls how many digits the result will have (since 0 == a == aaaaa).

elifiner
  • 7,347
  • 8
  • 39
  • 48
1

Sucks that python doesn't have what ruby has: String#next So here's a shitty solution to deal with alpha-numerical strings:

def next_string(s):
  a1 = range(65, 91)  # capital letters
  a2 = range(97, 123) # letters
  a3 = range(48, 58)  # numbers
  char = ord(s[-1])
  for a in [a1, a2, a3]:
    if char in a:
      if char + 1 in a:
        return s[:-1] + chr(char + 1)
      else:
        ns = next_string(s[:-1]) if s[:-1] else chr(a[0])
        return ns + chr(a[0])

print next_string('abc')  # abd
print next_string('123')  # 124
print next_string('ABC')  # ABD

# all together now
print next_string('a0')   # a1
print next_string('1a')   # 1b
print next_string('9A')   # 9B

# with carry-over
print next_string('9')    # 00
print next_string('z')    # aa
print next_string('Z')    # AA

# cascading carry-over
print next_string('a9')   # b0
print next_string('0z')   # 1a
print next_string('Z9')   # AA0

print next_string('199')  # 200
print next_string('azz')  # baa
print next_string('Zz9')  # AAa0

print next_string('$a')   # $b
print next_string('$_')   # None... fix it yourself

Not great. Kinda works for me.

Grocery
  • 2,244
  • 16
  • 26