Enumerating formatting strings

Michael Spencer mahs at telcopartners.com
Wed Apr 20 16:00:57 EDT 2005


Bengt Richter wrote:
> On Wed, 20 Apr 2005 11:01:28 +0200, Peter Otten <__peter__ at web.de> wrote:
> 
...
>>>>>"%s %(x)s %(y)s" % D()

My experiments suggest that you can have a maximum of one unnamed argument in a 
mapping template - this unnamed value evaluates to the map itself
>> ...
>> So under what circumstances is 
>>'%s this %(x)s not %% but %s' a valid format string?

Based on the above experiments, never.

I have wrapped up my current understanding in the following class:

  >>> s = StringFormatInfo('%s %*.*d %*s')
  >>> s
  POSITIONAL Template: %s %*.*d %*s
  Arguments: ('s', 'width', 'precision', 'd', 'width', 's')

  >>> s = StringFormatInfo('%(arg1)s %% %(arg2).*f %()s %s')
  >>> s
  MAPPING Template: %(arg1)s %% %(arg2).*f %()s %s
  Arguments: {'': 's', 'arg1': 's', 'arg2': 'f', None: 's'}
  >>>

class StringFormatInfo(object):
     parse_format = re.compile(r'''
         \%                                  # placeholder
         (?:\((?P<name>[\w]*)\))?            # 0 or 1 named groups
         (?P<conversion>[\#0\-\+]?)          # 0 or 1 conversion flags
         (?P<width>[\d]* | \*)               # optional minimum conversion width
         (?:.(?P<precision>[\d]+ | \*))?     # optional precision
         (?P<lengthmodifier>[hlL]?)          # optional length modifier
         (?P<type>[diouxXeEfFgGcrs]{1})      # conversion type - note %% omitted
         ''',
         re.VERBOSE
         )

     """Wraps a template string and provides information about the number and
        kinds of arguments that must be supplied.  Call with % to apply the
        template to data"""

     def __init__(self, template):
         self.template = template
         self.formats = formats = [m.groupdict() for m in 
self.parse_format.finditer(template)]

         for format in formats:
             if format['name']:
                 self.format_type = "MAPPING"
                 self.format_names = dict((format['name'], format['type'])
                             for format in formats)
                 break
         else:
             self.format_type = "POSITIONAL"
             format_names = []
             for format in formats:
                 if format['width'] == '*':
                     format_names.append('width')
                 if format['precision'] == '*':
                     format_names.append('precision')
                 format_names.append(format['type'])
             self.format_names = tuple(format_names)

     def __mod__(self, values):
         return self.template % values

     def __repr__(self):
         return "%s Template: %s\nArguments: %s" % \
                 (self.format_type, self.template, self.format_names)



Michael




More information about the Python-list mailing list