1

I have the custom formatter for string substitution, which is supposed to be only different from standard string formatter in replacement field syntax: instead of '{f}'.format(f=123) I want '$(f)'.format(f=123) (the latter is actually going to use the custom formatter class, like shell_formatter.format(...)).

I overrode the string.Formatter.parse to use new syntax, but the regular expression I'm using in the end doesn't quite satisfy me.

Questions:

  1. Can I get the regular expression to be simpler / more readable?
  2. Is there a simpler way to change formatting syntax, that I missed?

Updates

  1. Simplified the regexp and added new test.
  2. The purpose is to generate C source code files from a template. Using '{f}' syntax clearly will not work here because of C's excessive usage of curlys.
  3. The string.Template module doesn't support complex access specifiers (see third test).

The code follows:

#! /usr/bin/env python3

import string
import re


class ShellFormatter(string.Formatter):
    def parse(self, format_string):
        for m in re.finditer(
            r"""(?: \$ \( ( [^)]+ ) \) )   # the field access specifier
              | (
                    (?:
                        \n | . (?= \$ \( ) # any one single character before the '$('
                    )
                  | (?:
                        \n | . (?! \$ \( ) # any one single character, except the one before the '$('
                    )*
                )""",
            format_string,
            re.VERBOSE):

            if m.group(1):
                yield ('', m.group(1), '', None)

            if m.group(2):
                yield (m.group(2), None, None, None)


def main():
    ...


def test():
    s = 'ashyudiqhw $(field) fwekojnwe'
    ss = 'checking helll kpoqjkf3483297 18934417 hnhfnqi^$&*@&2 1748912$&#^$\n467812\n^$ jfimopw279\nashyudiqhw $(field) fwekojnwe\njjhjhj$(notfield)'
    sss = 'const int complex_stuff = $(stuff[0][field1][field2]);'
    sf = ShellFormatter()
    assert sf.format(s, field='zzz') == 'ashyudiqhw zzz fwekojnwe'
    assert sf.format(ss, field='zzz', notfield='xxx') == 'checking helll kpoqjkf3483297 18934417 hnhfnqi^$&*@&2 1748912$&#^$\n467812\n^$ jfimopw279\nashyudiqhw zzz fwekojnwe\njjhjhjxxx'
    assert sf.format(sss, stuff=[ { 'field1': { 'field2': '0x1234' } } ]) == 'const int complex_stuff = 0x1234;'


if __name__ == '__main__':
    test()
    main()
Michael Pankov
  • 3,581
  • 2
  • 23
  • 31

0 Answers0