[Tutor] String Formatting

Mike Hansen mhansen at cso.atmel.com
Fri Sep 10 23:50:55 CEST 2004


I found this in the Activestate Python Cookbook titled "Commafying an 
integer"

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146461

It might help.

Mike

>
> Subject:
> Re: [Tutor] String Formatting
> From:
> "Isr Gish" <isrgish at fastem.com>
> Date:
> Fri, 10 Sep 2004 17:21:49 -0400
> To:
> <kent_johnson at skillsoft.com>, <tutor at python.org>
>
> To:
> <kent_johnson at skillsoft.com>, <tutor at python.org>
>
>
>Thanks Kent, I'll try it when I get a chence.
>
>All the best,
>Isr
>
>
>-----Original Message-----
>   >From: "Kent Johnson"<kent_johnson at skillsoft.com>
>   >Sent: 9/10/04 12:08:16 PM
>   >To: "tutor at python.org"<tutor at python.org>
>   >Subject: Re: [Tutor] String Formatting
>   >
>   >I'm always up for an optimization challenge :-) I tried several methods. 
>   >Other than the locale-based solution, they all work for non-negative 
>   >integers only. Here is the fastest one I found. It takes about 1/10 the 
>   >time of the locale version and wouldn't be too hard to modify to work for 
>   >negative integers also.
>   >
>   >def commafy(val):
>   >     ''' Straightforward approach using string slices '''
>   >     s = str(val)
>   >     start = len(s) % 3
>   >
>   >     chunks = []
>   >     if start > 0:
>   >         chunks.append(s[:start])
>   >
>   >     for i in range(start, len(s), 3):
>   >         chunks.append(s[i:i+3])
>   >
>   >     return ','.join(chunks)
>   >
>   >Note that much of the time of the locale version is in accessing and 
>   >switching locales. If you can set the locale once before doing the 
>   >conversions, it is about 3x faster than the version that sets and restores 
>   >the locale.
>   >
>   >Here are all the versions I tried and a timing harness to compare them. The 
>   >output I get is this:
>   >commafy1: 1.052021 secs
>   >commafy2: 1.116770 secs
>   >commafy3: 1.067124 secs
>   >commafy4: 2.469994 secs
>   >commafy5: 1.125030 secs
>   >commafyLocale: 7.309395 secs
>   >commafyLocale2: 3.077568 secs
>   >
>   >Kent
>   >
>   >###############################################
>   ># commafy 1 to 3 are all variations on string slice and join
>   >def commafy1(val):
>   >     ''' Straightforward approach using string slices '''
>   >     s = str(val)
>   >     start = len(s) % 3
>   >
>   >     chunks = []
>   >     if start > 0:
>   >         chunks.append(s[:start])
>   >
>   >     for i in range(start, len(s), 3):
>   >         chunks.append(s[i:i+3])
>   >
>   >     return ','.join(chunks)
>   >
>   >
>   >def commafy2(val):
>   >     ''' Use list.extend() instead of an append loop '''
>   >     s = str(val)
>   >     start = len(s) % 3
>   >
>   >     chunks = []
>   >     if start > 0:
>   >         chunks.append(s[:start])
>   >
>   >     chunks.extend([s[i:i+3] for i in range(start, len(s), 3)])
>   >
>   >     return ','.join(chunks)
>   >
>   >
>   >def commafy3(val):
>   >     ''' Use a list comprehension instead of a loop. The initial
>   >         segment is a problem. '''
>   >     s = str(val)
>   >     start = len(s) % 3
>   >
>   >     chunks = [s[i:i+3] for i in range(start, len(s), 3)]
>   >     if start > 0:
>   >         chunks.insert(0, s[:start])
>   >
>   >     return ','.join(chunks)
>   >
>   >
>   >def commafy4(val):
>   >     ''' Iterate over the input and insert the commas directly '''
>   >     s = list(str(val))
>   >     s.reverse()
>   >     i = iter(s)
>   >     result = []
>   >     while True:
>   >         try:
>   >             result.append(i.next())
>   >             result.append(i.next())
>   >             result.append(i.next())
>   >             result.append(',')
>   >         except StopIteration:
>   >             if result[-1] == ',': result.pop()
>   >             break
>   >     result.reverse()
>   >     return ''.join(result)
>   >
>   >
>   >def commafy5(val):
>   >     ''' Use divmod to make the chunks '''
>   >     if val == 0: return '0'
>   >
>   >     chunks = []
>   >     while val > 999:
>   >         val, rem = divmod(val, 1000)
>   >         chunks.append(str(rem).zfill(3))
>   >     chunks.append(str(val))
>   >     chunks.reverse()
>   >     return ','.join(chunks)
>   >
>   >
>   >import locale
>   >def commafyLocale(val):
>   >     ''' Official solution using locale module '''
>   >     oldloc = locale.setlocale(locale.LC_ALL)
>   >     locale.setlocale(locale.LC_ALL, 'en')
>   >     result = locale.format('%d', val, True)
>   >     locale.setlocale(locale.LC_ALL, oldloc)
>   >     return result
>   >
>   >
>   >locale.setlocale(locale.LC_ALL, 'en')   # This line speeds up the ABOVE 
>   >version by 30% !
>   >def commafyLocale2(val):
>   >     ''' Use locale module but don't change locale '''
>   >     result = locale.format('%d', val, True)
>   >     return result
>   >
>   >
>   ># timing test
>   >import timeit
>   >def test(f):
>   >     return [f(10**i) for i in range(11)]
>   >
>   >correctAnswer = [
>   >'1',
>   >'10',
>   >'100',
>   >'1,000',
>   >'10,000',
>   >'100,000',
>   >'1,000,000',
>   >'10,000,000',
>   >'100,000,000',
>   >'1,000,000,000',
>   >'10,000,000,000',
>   >]
>   >
>   >def timeOne(fn):
>   >     # First run the function and check that it gets the correct results
>   >     actualAnswer = test(fn)
>   >     if actualAnswer != correctAnswer:
>   >         print fn.__name__, 'does not give the correct answer'
>   >         print actualAnswer
>   >         return
>   >
>   >     # Now time it
>   >     setup = "from __main__ import test, " + fn.__name__
>   >     stmt = 'test(%s)' % fn.__name__
>   >
>   >     t = timeit.Timer(stmt, setup)
>   >     secs = t.timeit(10000)
>   >     print '%s: %f secs' % (fn.__name__, secs)
>   >
>   >
>   >fnsToTest = [
>   >     commafy1,
>   >     commafy2,
>   >     commafy3,
>   >     commafy4,
>   >     commafy5,
>   >     commafyLocale,
>   >     commafyLocale2,
>   >]
>   >
>   >for fn in fnsToTest:
>   >     timeOne(fn)
>   >
>   >
>   >At 10:34 AM 9/10/2004 -0400, Isr Gish wrote:
>   >>Thanks orbitz,
>   >>
>   >>But...
>   >>
>   >>    >oldloc = locale.setlocale(locale.LC_ALL)
>   >>    >locale.setlocale(locale.LC_ALL, 'en_US')
>   >>    >locale.format('%d', some_num, True)
>   >>    >locale.setlocale(locale.LC_ALL, oldloc)
>   >>    >
>   >>
>   >>I would rather not use this way, iit takes about 25 times longer then a 
>   >>regular % format. And I'm using it for about 1,000,000 times.
>   >>
>   >>Isr
>   >>
>   >>-----Original Message-----
>   >>    >From: "orbitz"<orbitz at ezabel.com>
>   >>    >Sent: 9/9/04 10:55:22 PM
>   >>    >To: "Isr Gish"<isrgish at fastem.com>, "tutor at python.org"<tutor at python.org>
>   >>    >Subject: Re: [Tutor] String Formatting
>   >>    >
>   >>    >Easiest way would probably be using locale.format in some code I do:
>   >>    >
>   >>    >oldloc = locale.setlocale(locale.LC_ALL)
>   >>    >locale.setlocale(locale.LC_ALL, 'en_US')
>   >>    >locale.format('%d', some_num, True)
>   >>    >locale.setlocale(locale.LC_ALL, oldloc)
>   >>    >
>   >>    >
>   >>    >Isr Gish wrote:
>   >>    >
>   >>    >>Hi,
>   >>    >>
>   >>    >>How can I format a integer in a format string with a comma for example
>   >>    >>print 'Your Account has %f' %amount
>   >>    >>That should print:
>   >>    >>Your Account has 1,000.00
>   >>    >>
>   >>    >>Thanks
>   >>    >>Isr
>   >>    >>
>   >>    >>_______________________________________________
>   >>    >>Tutor maillist  -  Tutor at python.org
>   >>    >>http://mail.python.org/mailman/listinfo/tutor
>   >>    >>
>   >>    >>
>   >>    >>
>   >>    >
>   >>
>   >>_______________________________________________
>   >>Tutor maillist  -  Tutor at python.org
>   >>http://mail.python.org/mailman/listinfo/tutor
>   >
>   >_______________________________________________
>   >Tutor maillist  -  Tutor at python.org
>   >http://mail.python.org/mailman/listinfo/tutor
>  
>
>


More information about the Tutor mailing list