3

Is there any string formatting for using correct suffix with log messages, for example:

for n in itertools.count():
  print 'printing for the {:nth} time'.format(n)

Expected output:

printing for the 0th time
printing for the 1st time
printing for the 2nd time
printing for the 3rd time
printing for the 4th time
printing for the 5th time
...
printing for the 23rd time
...
printing for the 42nd time
...
etc

I could roll my own fairly easily, but I was wondering if there was already a built-in solution. If not, I will accept as answer the most elegant solution!

wim
  • 338,267
  • 99
  • 616
  • 750
  • 3
    See [this question](http://stackoverflow.com/questions/739241/python-date-ordinal-output). – DSM Feb 20 '12 at 01:19

2 Answers2

8

What about simply:

def stringify(x):
  if x // 10 % 10 == 1:
    return str(x) + 'th'
  else:
    return str(x) + { 1:'st', 2:'nd', 3:'rd' }.get(x % 10, 'th')

Or if you prefer ugly hacks:

return str(x) + { 1:'st', 2:'nd', 3:'rd' }.get(x//10%10 != 1 and x%10, 'th')

I felt a bit dirty while writing that one.

Niklas B.
  • 92,950
  • 18
  • 194
  • 224
  • Fascinating, when you write it out this way, you can see how the pronunciation of "[N hundred and] eleventh"-"twentieth" is unaffected by the special linguistic rules, while "twenty-first"/21st is not "twenty-oneth"/21th. How frightening. I for one did not realize the rules were so peculiar until I saw this. – ninjagecko Feb 20 '12 at 02:13
  • well, it works - not sure it's very elegant though. can it be done to extend str.format, so that the interface can be used like in my example in the question? – wim Feb 20 '12 at 02:28
  • @wim: well, you can always monkeypatch it ;) I don't believe that there exists an interface for adding formatters, though, so it'll get ugly. – Niklas B. Feb 20 '12 at 12:44
0
ordinal = lambda x: str(x) + ['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th'][0 if int(str(x)[-2:]) > 9 and int(str(x)[-2:]) < 21 else int(str(x)[-1])]

Not extremely efficient, but definitely a one-liner ;)

Joel Cornett
  • 24,192
  • 9
  • 66
  • 88