2017-01-19 35 views
0

我使用str.format_map來格式化某些字符串,但是當這個字符串包含引號時甚至會轉義,我遇到問題。下面是代碼:當使用str.format_map()時,超出了最大字符串遞歸

class __FormatDict(dict): 
    def __missing__(self, key): 
     return '{' + key + '}' 

def format_dict(node, template_values): 
    template_values = __FormatDict(template_values) 
    for key, item in node.items(): 
     if isinstance(item, str): 
      node[key] = item.format_map(template_values) 

對於reqular字符串(不包括括號或引號)它的工作原理,但是對於像"{\"libraries\":[{\"file\": \"bonjour.so\", \"modules\":[{\"name\": \"hello\"}]}]}"字符串它與消息ValueError: Max string recursion exceeded崩潰。

在格式化之前使用json.dumps(item)轉義引號並不能解決問題。應該做些什麼來解決這個問題?我正在修改從JSON文件中獲得的字符串,我寧願修復Python代碼,而不是更新我使用的JSON文檔。

回答

2

您無法在JSON數據上使用您的__missing__技巧。有很多問題。這是因爲{...}替換字段中的文字不僅僅是,而是。看看the syntax grammar

replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}" 
field_name  ::= arg_name ("." attribute_name | "[" element_index "]")* 

在替換域中,!...:...有意義呢!進入這些部分的內容也有嚴格的限制。

遞歸錯誤來自佔位符內佔位符內的多個嵌套{...}佔位符; str.format()str.format_map()不能支持大量的嵌套層次:

>>> '{foo:{baz: {ham}}}'.format_map({'foo': 'bar', 'baz': 's', 'ham': 's'}) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: Max string recursion exceeded 

但是這裏還有其他問題:

  • :結腸表示formatting specification,然後將其傳遞給對象(key)來自:之前的部分。如果您想要恢復這些值,則必須使用__format__方法爲__missing__返回值提供包裝器對象。

  • 其中.[...]的字段名也有特殊含義; "bonjour.so"將被解析爲"bonjour密鑰,具有so屬性。字段名稱中的[...]同上,但是用於項目查找。

最後兩可通過返回__format____getitem____getattr__方法包裝對象走近,但只在有限的情況下:

>>> class FormatWrapper: 
...  def __init__(self, v): 
...   self.v = v 
...  def __format__(self, spec): 
...   return '{{{}{}}}'.format(self.v, (':' + spec) if spec else '') 
...  def __getitem__(self, key): 
...   return FormatWrapper('{}[{}]'.format(self.v, key)) 
...  def __getattr__(self, attr): 
...   return FormatWrapper('{}.{}'.format(self.v, attr)) 
... 
>>> class MissingDict(dict): 
...  def __missing__(self, key): 
...   return FormatWrapper(key) 
... 
>>> '{"foo.com": "bar[baz]", "ham": "eggs"}'.format_map(MissingDict()) 
'{"foo.com": "bar[baz]", "ham": "eggs"}' 
>>> '{"foo .com": "bar [ baz ]", "ham": "eggs"}'.format_map(MissingDict()) 
'{"foo .com": "bar [ baz ]", "ham": "eggs"}' 

這失敗的「空白」屬性:

>>> '{"foo...com": "bar[baz]", "ham": "eggs"}'.format_map(MissingDict()) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: Empty attribute in format string 

簡而言之,格式對於包含的內容做了太多的假設ide {...}花括號,假設JSON數據很容易中斷。

我建議你看看使用string.Template() class來代替一個更簡單的模板系統,它可以被子類化;默認是查找並替換$identifier字符串。 Template.safe_substitute() method完全符合你的要求;替換已知的$identifier佔位符,但保留未知名稱不變。

相關問題