Обращение строк формата в стиле C в Python (`%`)

Введение и настройка

Предположим, у меня есть строка «шаблон»* формы,

>>> template = """My %(pet)s ate my %(object)s.
... This is a float: %(number)0.2f.
... %(integer)10d is an integer on a newline."""

С помощью этого шаблона я могу сгенерировать новую строку с помощью

>>> d = dict(pet='dog', object='homework', number=7.7375487, integer=743898,)

>>> out_string = template % d

>>> print(out_string)
My dog ate my homework.
This is a float: 7.74.
    743898 is an integer on a newline.

Как мило!

Вопрос

Я хочу применить template к out_string, чтобы создать новый dict. Что-то типа,

>>> d_approx_copy = reverse_cstyle_template(out_string, template)
>>> print(d_approx_copy)
{pet='dog', object='homework', number=7.74, integer=743898,}

Есть ли питонический способ сделать это? Реализация уже существует?**

Заметки

*: я не использую Шаблон, потому что, насколько я знаю, в настоящее время они не поддерживают реверс.

**: мне известны риски, связанные с потерей точности в number (от 7.7375487 до 7.74). Я могу справиться с этим. Я просто ищу простой способ сделать это.


person farenorth    schedule 16.10.2014    source источник
comment
я думаю, что нет необходимости в теге регулярного выражения..   -  person Avinash Raj    schedule 16.10.2014


Ответы (1)


Когда я разрабатывал этот вопрос, я не смог найти существующий инструмент для реверсирования строк в стиле C таким образом. То есть я думаю, что ответ на этот вопрос таков: функция reverse_cstyle_template, которую я искал, в настоящее время не существует.

В процессе изучения этой темы я нашел много вопросов/ответов, похожих на этот, в которых используется регулярные выражения (например, 1, 2, 3). Однако я хотел чего-то более простого и не хотел использовать другую строку шаблона для форматирования и синтаксического анализа.

В конечном итоге это привело меня к синтаксису строки форматирования и Ричард Джонс' анализировать пакет. Например, приведенный выше шаблон написан с использованием синтаксиса строки формата:

>>> template = """My {pet} ate my {object}.
... This is a float: {number:0.2f}.
... {integer:10d} is an integer on a newline."""

С помощью этого шаблона можно использовать встроенный str.format для создания новой строки на основе d,

template.format(**d)

Затем используйте пакет parse, чтобы получить d_approx_copy,

>>> from parse import parse
>>> d_approx_copy = parse(template, out_string).named

Обратите внимание, что я получил доступ к атрибуту .named. Это связано с тем, что parse возвращает объект Result (определенный при синтаксическом анализе), который содержит как описатели формата named, так и fixed. Например, если кто-то использует,

>>> template = """My {pet} {}ate my {object}.
... This is a float: {number:0.2f}.
... {integer:10d} is an integer on a newline.
... Here is another 'fixed' input: {}"""

>>> out_string = template.format('spot ', 7, **d)

>>> print(out_string)
My dog spot ate my homework.
This is a float: 7.74.
    743898 is an integer on a newline.
Here is another 'fixed' input: 7

Затем мы можем вернуть фиксированные и именованные данные,

>>> data = parse.parse(template, out_string)

>>> print(data.named)
{'pet': 'dog', 'integer': 743898, 'object': 'homework', 'number': 7.74}

>>> print(data.fixed)
('spot ', '7')

Круто, правда?!

Надеюсь, когда-нибудь эта функция будет встроена либо в str, либо в Шаблон. На данный момент parse хорошо работает для моих целей.

Наконец, я думаю, что важно еще раз подчеркнуть потерю точности, которая происходит на этих шагах при указании точности в спецификаторе формата (т. е. 7.7375487 становится 7.74)! В целом использование спецификатора точности, вероятно, является плохой идеей, за исключением случаев создания «читаемых» строк (например, для вывода «сводного» файла), которые не предназначены для дальнейшей обработки (т. е. никогда не будут анализированы). Это, конечно, сводит на нет суть данного вопроса/ответа, но здесь необходимо упомянуть.

person farenorth    schedule 16.10.2014