Python string.Formatter - 取得 format string 中的 placeholders
Posted on Mar 14, 2018 in Python 程式設計 - 高階 by Amo Chen ‐ 2 min read
有時候我們需要取得 format string(例如: This is a format string: Hello, {name}
)中的 placeholders(例如: {name}
)進行比較,例如檢查翻譯人員是否不小心把翻譯字串中的 placeholder 給遺漏了,因為這可能會造成翻譯後的字串漏字。
所幸這種需求可以透過 string.Formatter
幫忙取得字串中的 placeholders 。
直接看範例:
>>> from string import Formatter
>>> iterable = Formatter().parse('{greeting} {name}, this is an example')
>>> iterable
<formatteriterator object at 0x101cba0c0>
>>>
>>> for r in iterable:
... print(r)
...
('', 'greeting', '', None)
(' ', 'name', '', None)
(', this is an example', None, None, None)
上述可以看到 Formatter().parse('{greeting} {name}, this is an example')
在解析完 format string 後會回傳一個 formatteriterator
object ,接著我們走訪這個 object 取出每一個結果,每個結果都是一個長度 4 的 tuple ,分別代表的是 (literal_text, field_name, format_spec, conversion)
,其中 field_name
就是我們想要的資訊,因此要比對 2 個字串是否含有相同 placeholders 時,只要比對 field_name
即可。
接著,稍微淺談一下 format_spec
與 conversion
。
Format string 可以有所謂的 format specification 與 conversion ,例如: {number:,.2f}
中的 ,.2
代表數字超過千分位顯示逗號以及顯示到小數點後第 2 位,這就是 format_spec
。
>>> '{number:,.2f}'.format(number=1000.1314)
'1,000.13'
>>>
>>> for r in Formatter().parse('{number:,.2f}'):
... print(r)
...
('', 'number', ',.2f', None)
而 conversion 目前則有 3 種表示方式,分別為 !s
, !r
與 !a
,分別代表 1 個變數在被放進 placeholder 之前會分別用 str()
, repr()
, ascii()
呼叫。
Three conversion flags are currently supported: ‘!s’ which calls str() on the value, ‘!r’ which calls repr() and ‘!a’ which calls ascii().
p.s. 由於 ascii()
用到的情況相對少,跟 repr()
行為也很像,因此在此不討論
直接看個範例會更加了解文件的意思,以下模擬 1 個 class 有 2 種 methods ( __str__
, __repr__
) ,然後分別看他們被放到不同 conversion 的 format string 會發生何事:
class User(object):
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
def __repr__(self):
return 'User("{}")'.format(self.name)
user = User('amo')
print('str -> {!s}'.format(user))
print('repr -> {!r}'.format(user))
執行上述程式會出現以下結果:
str -> amo
repr -> User("amo")
看到這就可以明白 user
被放到 format string 之前,被分別用 str(user)
與 repr(user)
取得結果後再放進去 format string ,最後變成我們看到的樣子。
p.s. 關於 str()
與 repr()
為什麼會執行 __str__
與 __repr__
可以參考 object.__str__
以上, Happy Coding!