2016-06-14 6 views
-1

형식 문자열 사전 계단식/재귀 적 문자열 보간을 수행하고 싶습니다. 파이썬에서 계단식 문자열 보간

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() 함수는 먼저 형식 문자열을 선택합니다. 그런 다음 형식 문자열이 더 이상 남아 있지 않을 때까지 문자열을 대체합니다. 나는 다음과 같은 파이썬 사전이 함수를 호출 할 때

, 내가 얻을 :

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

결과는 OK입니다 만, 그러한 구현은 참조주기를 감지하지 않습니다.

예를 들어 다음 호출을하면 무한 루프가 발생합니다.

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

아무에게도 더 나은 구현을 제공 할 수 있습니까?

편집 : 솔루션

나는 레온의 솔루션은 너무 서지 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

*? "누군가가 나에게 더욱 향상된 기능을 제공 할 수"* - 그건 SO가있는 것이 아닙니다. 해결하려는 실제 문제는 무엇입니까 - 참조주기가있는 입력을 실제로 얻을 수 있습니까? – jonrsharpe

+0

* "더 나은 구현을 제공 할 수 있습니까?"* - 주어진 입력에 대해 정확히 동일한 결과를 생성해야합니까? –

+0

사실, 나는 일반적인 해결책을 찾고있다. 예시는 설명을위한 것입니다. 예, 폴더를 정의하는 사용자가 일반적으로 구성 파일 (예 :''interpolate()''함수에서 오류를 만드는 경우주기를 가질 수 있습니다. –

답변

1

쉽게 루프에 대한 이러한 참조주기를 확인할 수 있습니다

나는 그런 식으로 구현하는 것입니다. for 루프 내의 일치하는 값에서 키가 참조되는지 확인하십시오.

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