2013-12-19 16 views
17

Python文字列のformat()を使用して、素早く汚れたテンプレートとして機能させたいと考えています。しかし、私が使用したいdictは、整数の(文字列表現である)キーを持っています。簡単な例は次のとおり整数キーでdictを使用したPython文字列形式()

s = 'hello there {5}' 
d = {'5': 'you'} 
s.format(**d) 

上記のコードは、次のエラーをスロー:

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
IndexError: tuple index out of range 

は、上記を実行することが可能ですか?

+5

「str」は変数名として使用しないでください。これは、組み込みの 'str'クラスをオーバーライドするためです。 – Volatility

+0

'{[5]}'はキーが実際に整数だった場合に機能します。 – Blender

答えて

27

我々は、それが動作しないことを確立し、どのように解決策に関するました:

str.formatがfunnily十分古い%が意志をフォーマット、この場合には動作しませんが。これは推奨されていませんが、素早く汚れたテンプレートを求めました。

>>> 'hello there %(5)s' % {'5': 'you'} 
'hello there you' 

ただし、これは整数キーでは機能しません。

>>> 'hello there %(5)s' % {5: 'you'} 

Traceback (most recent call last): 
    File "<pyshell#1>", line 1, in <module> 
    'hello there %(5)s' % {5: 'you'} 
KeyError: '5' 
+0

完璧!まさに私が何をしていたのか。 – yee379

6

問題の答えはthis postを参照してください。書式文字列(docs link)の辞書キーとして数字で構成される文字列を使用することはできないようです。

あなたが5以外のキーを使用することができるなら、それは動作します:

my_string='hello there {spam:s}' 
d={'spam': 'you'} 
print my_string.format(**d) # Returns "hello there you" 
+2

リンクされた答えの最も重要な部分は、ドキュメントの引用です: 'arg_nameは引用符で区切られていないため、任意の辞書キー(例えば '10'や ': - 'など)を指定することはできません書式文字列。 – Blckknght

3

str.formatで使用PEP 3101

The built-in string class (and also the unicode class in 2.6) will gain a new method, 'format', which takes an arbitrary number of positional and keyword arguments:

"The story of {0}, {1}, and {c}".format(a, b, c=d) 

Within a format string, each positional argument is identified with a number, starting from zero, so in the above example, 'a' is argument 0 and 'b' is argument 1. Each keyword argument is identified by its keyword name, so in the above example, 'c' is used to refer to the third argument.

数値が位置しているから議論そうすることはできません。

hereからPEP 3101にアクセスできます。関連するセクションはです。文字列メソッド

@Volatilityは前述のように、%フォーマッタを使用することができます。

1

あなたは引数キーにインデックスに戻って落ちる前に辞書のキーとして交換用のフィールドをしようとするカスタムstring.Formatterget_valueで何かを行うことができます - ここでは、優先度や意図の可能性の競合に注意してください...それはまさにお勧めしませんしかし、可能ですかのアイデア:

import string 

class MyFormatter(string.Formatter): 
    def get_value(self, key, args, kwargs): 
     try: 
      return kwargs[str(key)] 
     except KeyError: 
      return super(MyFormatter, self).get_value(key, args, kwargs) 

s = 'hello there {5} - you are number {0}' 
d = {'5': 'you'} 
print MyFormatter().format(s, 1, 2, 3, **d) 
# hello there you - you are number 1 
0

これは、言及することはほとんどあまりにも醜いですが、位置的に引数を渡すことによって一緒にそれをハックすることができます。それはちょっとうまくいくが、私はこれを投稿するとかなり汚いと感じる!

>>> def myformat(s, d): 
... return s.format(*[d.get(str(n)) for n in range(1 + int(max(d, key=int)))]) 
... 
>>> d = {'5': 'you'} 
>>> myformat('hello {5}', d) 
'hello you' 
>>> myformat('hello {5} {5}', d) 
'hello you you' 
>>> d['2'] = 'Oh!!' 
>>> myformat('{2} hello {5} {5}', d) 
'Oh!! hello you you' 

は、残念ながら、Pythonであなたがstrにそれをパッチを適用することはできません、あなたはTypeError: can't set attributes of built-in/extension type 'str'を取得します。

あなたはdictのdを管理している場合は、私ははるかに優れたソリューションが、それは任意のフィールドを許可するように、私はフォーマッタを拡張する考えを愛するだけでパッドに数字アンダースコアを含む文字列か何かk.i.s.s.

8

だと思います名前(整数、コロンなどのフィールド名)。バッククォート内のフィールドは、文字通りに扱われるので

d = {'5': 'you', '6': 'me', "okay":1, "weird:thing!": 123456} 
print QuFormatter().format(
    'hello there {`5`} {`6`:20s}--{okay}--{`weird:thing!`:20,d}', 
    **d) 

import string, re 

class QuFormatter(string.Formatter): 
    def _quote(self, m): 
     if not hasattr(self, 'quoted'): 
      self.quoted = {} 
     key = '__q__' + str(len(self.quoted)) 
     self.quoted[key] = m.group(2) 
     return '{' + m.group(1) + key + m.group(3) + '}' 

    def parse(self, format_string): 
     return string.Formatter.parse(self, 
      re.sub(r'{([^}`]*)`([^}`]*)`([^}]*)}', self._quote, format_string)) 

    def get_value(self, key, args, kwargs): 
     if key.startswith('__q__'): 
      key = self.quoted[key] 
     return string.Formatter.get_value(self, key, args, kwargs) 

使用方法:実装は次のようになります。

+1

私のkludgeよりはるかにエレガントなアプローチ;-) –

0

実際に{k}というファクトを使用して、位置の引数(k+1)を探すことができます。

def populate_list(d): 
    """ Return a list l verifying l[k] = d[str(k)] for each natural k """ 
    return [d.get(str(k)) for k in range(1 + max(map(int, d)))] if d else [] 

def format_with_int_keys(s,d): 
    """ Replace each {k} in s by d[str(k)] """ 
    return s.format(*populate_list(d)) 

s = 'hello there {5}' 
d = {'5': 'you'} 
print (format_with_int_keys(s,d)) 

編集:それは実際に@wimソリューションの詳細版です。

関連する問題