2016-06-14 5 views
-1

Учитывая словарь строк формата, Я хочу сделать каскадную/рекурсивную интерполяцию строк.Каскадная строковая интерполяция в python

FOLDERS = dict(home="/home/user", 
       workspace="{home}/workspace", 
       app_project="{workspace}/{app_name}", 
       app_name="my_app") 

Я начал с этой реализации:

def interpolate(attrs): 
    remain = [k for k, v in attrs.items() if "{" in v] 
    while remain: 
     for k in remain: 
      attrs[k] = attrs[k].format(**attrs) 
     remain = [k for k in remain if "{" in attrs[k]] 

interpolate() функция первого выбора строки форматирования. Затем он заменяет строки, пока не останется больше строк формата.

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

>>> import pprint 
>>> pprint.pprint(FOLDERS) 
{'app_name': 'my_app', 
'app_project': '/home/user/workspace/my_app', 
'home': '/home/user', 
'workspace': '/home/user/workspace'} 

В результате в порядке, но эта реализация не обнаруживает опорные циклы.

Например, следующий вызов вызывает бесконечный цикл!

>>> interpolate({'home': '{home}'}) 

Может ли кто-нибудь дать мне лучшую реализацию?

EDIT: решение

Я думаю, что решение Леона хорошо и просто, один из Serge Bellesta тоже.

Я реализовать это таким образом:

def interpolate(attrs): 
    remain = [k for k, v in attrs.items() if "{" in v] 
    while remain: 
     for k in remain: 
      attrs[k] = attrs[k].format(**attrs) 
      fmt = '{' + k + '}' 
      if fmt in attrs[k]: # check for reference cycles 
       raise ValueError("Reference cycle found for '{k}'!".format(k=k)) 
     remain = [k for k in remain if "{" in attrs[k]] 
+2

* «? Может кто-нибудь дать мне лучшую реализацию» * - это не то, для чего СО. Какова фактическая проблема, которую вы пытаетесь решить - действительно ли вы получите какие-либо входы с эталонными циклами? – jonrsharpe

+0

* «Может ли кто-нибудь дать мне лучшую реализацию?» * - Нужно ли только производить точные результаты для данного ввода? –

+0

Если факт, я ищу универсальное решение. Образцы предназначены только для иллюстрации. Да, у нас могут быть циклы, если пользователь, который определяет папки, создает ошибку - обычно - файлы конфигурации: функция '' interpolate() '' должна найти ее. –

ответ

1

Вы можете проверить для таких опорных циклов в течение цикла легко. Просто проверьте, если ключ ссылается на значение соответствия в пределах цикл:

def interpolate(attrs): 
    remain = [k for k, v in attrs.items() if "{" in v] 
    while remain: 
     for k in remain: 
      attrs[k] = attrs[k].format(**attrs) 
      if '{%s}' % k in attrs[k]: # check for reference cycles 
       raise ValueError("Input contains at least one reference cycle!") 
     remain = [k for k in remain if "{" in attrs[k]] 

Теперь, если есть ссылка цикла, возникает ошибка. Это будет определять опорные циклы любой длины, поскольку они заменяются до тех пор, пока не будут найдены или все подстановки не будут завершены.

0

Если ваша единственная проблема в том, чтобы обнаружить циклические ссылки, чтобы избежать бесконечных циклов, вы можете остановиться, как только одна интерполяция возвращает вход:

def interpolate(attrs): 
    remain = [k for k, v in attrs.items() if "{" in v] 
    while remain: 
     for k in remain: 
      attrs[k] = attrs[k].format(**attrs) 
     temp = [k for k in remain if "{" in attrs[k]] 
     if temp == remain: 
      # cyclic reference detected 
      ... 
     remain = temp 
Смежные вопросы