frans
frans

Reputation: 9758

Is it possible to write nested format strings?

I want to write something like

format_specifier = "{some_dict[some_key]}"

to later use it together with .format():

result = format_specifier.format(some_dict={"one": "eins", "two": "zwei"}, some_key="one")

which I wanted to evaluate to "eins", but instead I get a KeyError:

KeyError: 'some_key'

I also tried extra braces: "{some_dict[{some_key}]}" resulting in KeyError: '{some_key}'..

Is nesting format strings like this possible in the first place?

Note: I have to evaluate the string later so I guess f-string formatting is not an option for me..

Upvotes: 1

Views: 717

Answers (2)

frans
frans

Reputation: 9758

Inspired by rioV8 I now do it like this, but I think it can be simplified very much if not Python has a built-in method to do this:

def formatComplex(specifier: str, format_data):
    result = specifier
    while True:
        matches = re.findall(".*{([A-Za-z0-9_\-\/\ \,\.\'\"\(\)\[\]]+)}.*", result)
        if not matches:
            break
        for m in matches:
            result = result.replace("{%s}" % m, str(eval(m, None, format_data)))
            
    return result
>>> format_specifier = "{some_dict[another_dict[some_key]]} world"
>>> formatComplex(format_specifier, {
...    "some_dict": {3: "Hello"}, 
...    "another_dict": "three": 3}, 
...    "some_key":"three"})
Hello world
>>> formatComplex("Hello {who} {what} bar", {"who": "world", "what": "foo"})
Hello world foo bar

Upvotes: 0

rioV8
rioV8

Reputation: 28643

If you use eval and define your used format arguments as a collection of local variables you can evaluate the format string.

format_specifier = "some_dict[another_dict[some_key]]"

def formatComplex(str, **kwargs):
  # check str for correct format: only regex [a-zA-Z0-9\[\]] allowed
  return eval(str, None, kwargs)

result = formatComplex(format_specifier, some_dict={3:"Hello"}, another_dict={"bla":3}, some_key="bla")

print (result)

You can add this to your string formatting by writing your own string.Formatter sub class and implement a new parse() method that substitutes these complex formats into literal text

Upvotes: 1

Related Questions