Расширенное форматирование строк Python с пользовательскими заполнителями?

У меня есть следующий шаблон HTML в переменной Python:

template = """
    <script>
        function work()
        {
            alert('bla');
        }
    </script>

    Success rate is {value:.2%} percent.
"""

Я хочу подставить {value:.2%} некоторым десятичным числом с соответствующим форматированием. Поскольку мой шаблон может содержать много JavaScript-кода, я хочу избежать экранирования фигурных скобок с помощью {{ и }}, поэтому использование template.format(...) напрямую не является вариантом.

Использование Template(template).substitute(...) также представляется невозможным, потому что я хочу расширенное форматирование для value.

Я мог бы заменить {value:.2%} соответствующим синтаксисом %(value)..., а затем использовать template % .... Но я не являюсь поклонником этого синтаксиса, потому что для большинства переменных в реальном мире шаблону не требуется расширенное форматирование, поэтому я хочу, чтобы синтаксис заполнителя был простым.

Итак, мой вопрос в том, можно ли использовать шаблоны в шаблоне, которые позволяли бы форматировать при необходимости, т.е. просто {{value}} или [[value]], а также {{value:.2%}} или [[value:.2%]]?

Изменить: Наконец, я хочу избежать ошибок, которые создавал бы .format(...), когда шаблон содержит заполнители, например {{dont_want_this_substituted}}, для которых переданный словарь не содержит значения. То есть, я хочу только заменить только определенные заполнители, а не все, что отображается в шаблоне.

Изменить 2: Чтобы добиться того, чего я хочу, я могу сначала захватить все заполнители с помощью регулярного выражения, затем отформатировать их содержимое и, наконец, сделать замену в шаблоне. Но мне интересно, существует ли более простое решение.

Изменить 3: Было предложено разбить шаблон, чтобы избежать проблем с format(). Однако я хотел бы избежать этого, потому что шаблон фактически исходит из файла.

Ответ 1

Просто предварительно обработайте шаблон. Например, если вы хотите, чтобы [[...]] был вашим маркером шаблона и оставил только одиночные символы { и }:

template = """
    <script>
        function work()
        {
            alert('bla');
        }
    </script>

    Success rate is [[value:.2%]] percent.
"""

result = template.replace("{", "{{").replace("}", "}}").replace("[[", "{").replace("]]", "}").format(value=0.8675309)

Попытка сделать все это с разным количеством фигурных скобок сложна, поэтому я определенно буду использовать некоторые другие персонажи. Однако осторожно, что такие вещи, как [[ и ]], могут иметь место в законном коде JavaScript. Возможно, лучше использовать то, что никогда не могло.

Ответ 2

Забудьте регулярное выражение и предварительную обработку. Вы должны разбить шаблон так, чтобы переменные части не были в той же строке, что и части <script>.

head = """
    <script>
        function work()
        {
            alert('bla');
        }
    </script>
"""


template = """
    {head}

    Success rate is {value:.2%} percent.
"""

Наконец, я хочу избежать ошибок, которые будет возникать .format(...), когда шаблон содержит заполнители, такие как {{dont_want_this_substitution}}, для которых переданный словарь не содержит значения. То есть, я хочу только заменить только определенные заполнители, а не все, что отображается в шаблоне.

Это может быть взломано, но вы можете использовать collections.defaultdict, как показано в этом ответе. Образец кода из этого ответа (изменено).

from collections import defaultdict

my_csv = '{optional[first]},{optional[middle]},{optional[last]}'
print( my_csv.format( optional=defaultdict(str, first='John', last='Doe') ) )