使用者:Xyy23330121/Python/格式化字符串

格式化字符串是一種字符串處理的方法。

str.format()方法

編輯

str.format 方法可以按模式更改字符串中的內容。我們用以下示例來展示該方法的特徵:

a = "{} World"
print(a)                 #输出:{} World
print(a.format("Hello")) #输出:Hello World
print(a)                 #输出:{} World

可以看出,a.format("Hello") 輸出了字符串 a 被替換掉大括號 {} 的版本,沒有更改字符串本身。

我們可以按順序設置以下內容,從而進行更高級的替換。

設置用於替換的參數

編輯

按順序指定

編輯

字符串中,如果不指定任何內容,大括號會被按輸入參數的順序替換。

print("{} {}".format("Hello", "World", "!"))  #输出:Hello World

按索引指定

編輯

大括號中間如果有索引,則會按輸入參數的索引替換內容。

print("{1} {2}".format("Hello", "World", "!"))  #输出:World !
print("{0} {0}".format("Hello", "World", "!"))  #输出:Hello Hello

按名稱(標識符)指定

編輯

大括號中間如果有標識符,則會按照標識符,查找傳入的參數名稱,來確定替換的內容。

print("{first} {second}".format(first = "Hello", third = "World", second = "!"))  #输出:Hello !
print("{third} {third}".format(first = "Hello", third = "World", second = "!"))  #输出:World World

索引和屬性

編輯

在指定了參數後,我們還可以進一步指定參數的元素或屬性。

使用索引

編輯

我們可以給輸入的內容指定索引。

print("{0[0]} {2}".format("Hello", "World", "!"))  #输出:H !

要注意,此時索引僅支持非負整數。如果輸入以下的內容,就會報錯:

print("{0[0:]} {2}".format("Hello", "World", "!"))
#TypeError: string indices must be integers, not 'str'

在替換時,Python 如果識別到方括號裡面有不在 0~9 中的字符,就會把索引作為字符串傳入。也就是說,在本例中,指定的替換內容是"Hello"["0:"],而非"Hello"[0:]。這對於參數是字典的時候很有幫助,但對於參數是字符串、元組或列表的時候則相反。

解決方法見之後的 章節。

使用屬性

編輯
print("{0.start} {2}".format(range(3), "World", "!"))  #输出:0 !

類似索引,我們也可以指定屬性。

索引 / 屬性可以多次使用

編輯

使用索引或屬性的次數是沒有限制的。比如:

print("{0[0][1]} {2}".format(["Hello"], "World", "!"))  #输出:e !

指定轉換方式

編輯
轉換方式列表
字符 意思
s str函數轉換
r repr函數轉換
a ascii函數轉換

在確定了用於替換的內容後,我們可以指定轉換方式。

print("{0[0]!s} {2}".format(["Hello"], "World", "!"))  #输出:Hello !

通過輸入 ! ,再輸入代表轉換方式的字符,我們可以決定如何把參數的內容轉換為字符串。以上面的0[0]!s為例,此時,Python 會用 str(0[0])(即 str(["Hello"][0]) )的內容去替換原字符串的內容。

repr 函數

編輯

repr 函數會嘗試返回一串字符串,使得程序員按照字符串輸入內容,就能直接生成對應的對象。比如:

print(str("114514"))  #输出:114514
print(repr("114514")) #输出:'114514'

如果程序員按照 repr 函數返回的字符串,輸入了 '114514'。那麼該程序員會得到與 repr 函數參數相同的一個對象。

備註
此處 <generator object <genexpr> at *> 中的*是程序運行時,該對象被存儲於內存中的位置,或者說,指向該對象的指針。在每次運行中,由於存儲對象所使用的內存位置不同,該值也是不同的。

但這也不絕對,比如:

print(str(i for i in range(3)))  #输出:<generator object <genexpr> at *>
print(repr(i for i in range(3))) #输出:<generator object <genexpr> at *>

repr 函數返回的結果,並非創建參數對象時使用的 i for i in range(3)。此時,哪怕使用 repr 函數,對於程序員得到相同的對象也毫無幫助。

ascii 函數

編輯

ascii函數會返回 repr 函數返回結果的轉義。它會將 repr 函數返回結果中、任何非 ascii 字符的內容,用轉義序列 \x\u\U來進行替代。

設置更多內容(格式規格迷你語言)

編輯

我們還可以用「格式規格迷你語言」設置更多內容。

print("{0!s:-^9}".format(123))  #输出:---123---

通過輸入 : ,再輸入格式規格迷你語言,我們可以進行更多設置。

對齊與填充選項

編輯
數字與轉換方式
注意到這裡有些設置僅對數字有效。如果要使用僅對數字有效的選項,則不應規定轉換方式。我們考慮以下內容:
print("{0!s:=}".format(123))
如果使用了 !s,則對於之後的設置 := 而言,傳入的參數就相當於 str(123),即'123'——這是個字符串。從而任意僅對數字類型有效的選項在此時都會出錯。

我們可以添加以下的字符,來表示如何進行對齊:

字符 解釋
< 左對齊 (這是大多數對象的默認值)
> 右對齊 (這是對數字的默認值)
^ 居中
= (僅對數字有效)在符號後填充

其中,=4 代表數字會被填充為 - 12 的形式——在符號後填充字符,而非右對齊時在符號左側進行填充。

在指定了對齊方式後,我們可以在對齊方式的字符之前添加一個字符,指定以該字符進行填充。比如:$< 代表左對齊,不足的部分用 $ 填充。

這些行為類似於之前學過的 字符串的操作:居中與對齊 的內容,與之前學過的內容類似,只有設置了字符串的長度、大於由 str.format 的參數得到的字符串的長度後,這裡的設置才有用。

符號列表
字符 解釋
+ 除負數要添加減號外,在正數前也添加一個加號。
- 僅在負數前添加減號。
(空格)在正數前添加一個空格作為符號。

符號選項(僅對數字類型有效)

編輯

我們可以設置數字前是否添加符號。詳細見右表。

z 選項:處理負零(僅對浮點數有效)

編輯

添加字符 z 以應用此選項。

在浮點數進行轉換後,有可能會出現-0-0.0之類的情況。這種情況一般是負的接近零的小數捨入導致的,也可能是轉換了 float("-0")

如果添加了字符z,Python 就會對這種情況進行修改。使其按照之前的符號選項,變為 0.0+0.0(空格)0.0

# 選項:保留符號

編輯

添加字符 # 以應用此選項。

對於整數,如果之後設置了以二進制、八進制或十六進制進行輸出。此選項會在輸出值前添加0b0o0x0X前綴。

對於浮點數和複數,它會使得轉換結果總是包含小數點(即使轉換結果不帶小數部分)。

對於 gG 轉換,末尾的零不會從結果中被移除。

0 選項

編輯

添加字符 0 以應用此選項。

在沒有設置「對齊與填充選項」時。對於數字,如果應用此選項,相當於將之前的「對齊與填充選項」設置為 0=,即「在符號後,用 0 進行填充」;而對於字符串或其它對象,相當於將填充字符設置為 0

如果設置了「對齊與填充選項」,則會優先使用「對齊與填充選項」中的設置。如果「對齊與填充選項」未指定填充字符,則該設置會將填充字符設置為 0

字符串長度

編輯

可以輸入正整數來決定字符串的長度。如果字符串未達到長度,就會按照之前「對齊與填充選項」的設置,對字符串進行填充。

分隔符

編輯

在分隔符這裡有兩個選項:,_

, 選項僅對浮點數和表示類型為 n 的整數有效,它會將 , 作為千位分隔符添加到整數或浮點數中。

_ 選項對浮點數或表示類型為 n 的整數時,會將 _ 作為千位分隔符添加到整數或浮點數中。而在使用二進制、八進制或十六進制輸出的時候,會每四個數字插入一個下劃線。

精度與字符串最大長度

編輯

通過添加 . 再輸入正整數,可以設置精度或字符串的最大長度。它僅對表示類型為 fFgG 的浮點數,以及對字符串有效。

對於表示類型為 eEfF 的浮點數,它代表小數點後應顯示的數位。

對於表示類型為 gG 的浮點數,它代表小數點前後總共顯示的數位。

對於字符串,它代表字符串的最大大小。如果超出這個大小,就會截斷之後的部分。

表示類型

編輯

最後,我們可以設置表示類型。

對字符串
編輯

字符串可使用的表示類型如下表:

選項 解釋
s (默認)作為字符串輸出
(省略) 使用默認選項
對整數
編輯

整數可使用的表示類型如下表:

選項 解釋
b 用二進制格式輸出
o 用八進制格式輸出
d (默認選項)用十進制格式輸出,不支持分隔符。
x 用十六進制格式輸出,輸出時使用小寫字母,比如 1bf52
X 用十六進制格式輸出,輸出時使用大寫字母,比如 1BF52
n 用十進制格式輸出,支持分隔符。
c 轉換成對應的 ascii 字符進行輸出。
(省略) 使用默認選項
對浮點數
編輯

浮點數可使用的表示類型如下表:

選項 解釋
e 用科學計數法輸出,默認精度為6,即小數點後默認保留6位。比如1.000000e0

特別的,和精度無關,nan 會輸出為 nan ,inf 會被輸出為 inf

E 用科學計數法輸出,但是中間的字符會大寫。nan 和 inf 也會被輸出為大寫。
f 用定點表示法輸出,默認精度為6,即小數點後默認保留6位。比如1.000000

特別的,和精度無關,nan 會輸出為 nan ,inf 會被輸出為 inf

F 類似 f,但 nan 和 inf 會被輸出為大寫。
g 用科學計數法表示時,如果指數部分大於等於-4而小於精度(默認精度為6),則會用定點表示法輸出。反之,用科學計數法輸出。

特別的,和精度無關,nan 會輸出為 nan ,inf 會被輸出為 inf,而正負零會被輸出為 0-0

G 類似 g,但輸出會大寫。
n 這種方式的輸出,按照 Python 文檔的說明:「類似g……」。由於 Python 文檔不夠詳細,我們在下面對照示例和輸出研究它的性質。
% 轉換成百分比格式進行輸出。具體來講,是將數字乘 100 ,然後用 f 格式輸出,再在輸出結果後添加一個百分號。
(省略) 這種方式的輸出,按照 Python 文檔的說明:「類似g……」。由於 Python 文檔不夠詳細,我們在下面對照示例和輸出研究它的性質。

以上表示類型還可以用於 decimal 對象。關於 decimal 類型,參見 Python 文檔,這裡不多敘述。關於這些表示類型對 decimal 對象的行為,請讀者查閱 Python 文檔進行補充。

關於浮點數表示類型 n 的示例及輸出

表示類型 n 時,對齊方式和填充、符號選項、z選項都會按照最平凡的方式產生作用。但分隔符、#選項等選項的行為值得進行一些測試。我們看以下示例:

#默认设置
#默认是使用小写。
print("{:n}".format(1000.0))        #输出:1000
print("{:n}".format(12.345))        #输出:12.345
print("{:n}".format(float("-inf"))) #输出:-inf
print("{:n}".format(float("nan")))  #输出:nan

#分隔符
#print("{:,n}".format(1000.0))      #输出:ValueError: Cannot specify ',' with 'n'.
#print("{:_n}".format(1000.0))      #输出:ValueError: Cannot specify '_' with 'n'.

#保留符号
#无论如何,保留小数点后2位。
print("{:#n}".format(1000.0))       #输出:1000.00
print("{:#n}".format(1234.5))       #输出:1234.50

#精度
#如果数字 > 10**精度,则四舍五入后输出定点表示法。反之,则四舍五入后输出科学计数法。
print("{:.3n}".format(1000.0))      #输出:1e+03
print("{:.4n}".format(1000.0))      #输出:1000
print("{:.3n}".format(12.345))      #输出:12.3
print("{:.2n}".format(12.345))      #输出:12
print("{:.1n}".format(12.345))      #输出:1e+01

#默认精度
#默认精度为6。
print("{:n}".format(1234567.0))     #输出:1.23457e+06

#保留符号 + 精度
#在保留符号 + 精度时,总是使输出的数字位数等于精度。
print("{:#.2n}".format(1000.0))     #输出:1.0e+03
print("{:#.3n}".format(1000.0))     #输出:1.00e+03
print("{:#.4n}".format(1000.0))     #输出:1000.
print("{:#.5n}".format(1000.0))     #输出:1000.0
print("{:#.3n}".format(float("-0")))#输出:-0.00
關於浮點數表示類型(省略)的示例及輸出

省略表示類型時,對齊方式和填充、符號選項、z選項以及單獨的保留符號選項都會按照最平凡的方式產生作用。但分隔符、#選項等選項的行為值得進行一些測試。我們看以下示例:

#默认设置
#默认设置使用小写
print("{}".format(1000.0))        #输出:1000.0
print("{}".format(12.345))        #输出:12.345
print("{}".format(float("-inf"))) #输出:-inf
print("{}".format(float("nan")))  #输出:nan

#分隔符
print("{:,}".format(1000.0))      #输出:1,000.0
print("{:_}".format(1000.0))      #输出:1_000.0

#精度
#如果数字 > 10**(精度+1),则四舍五入后输出定点表示法。反之,则四舍五入后输出科学计数法。
print("{:.4}".format(1000.0))      #输出:1e+03
print("{:.5}".format(1000.0))      #输出:1000.0

#默认精度
#默认精度足以精确表示输入的值。
print("{:}".format(1234567.0))     #输出:1234567.0

#保留符号 + 精度
#在保留符号 + 精度时,总是使输出的数字位数等于精度。
print("{:#.2}".format(1000.0))     #输出:1.0e+03
print("{:#.3}".format(1000.0))     #输出:1.00e+03
print("{:#.4}".format(1000.0))     #输出:1.000e+03
print("{:#.5}".format(1000.0))     #输出:1000.0
print("{:#.3}".format(float("-0")))#输出:-0.00

Python 文檔與語句語法

編輯

我們將利用這一章節的機會,簡單學習 Python 文檔中,語句語法的表現形式。在本章節所述的 Python 文檔中,我們看到了以下的內容。

replacement_field ::=  "{" [field_name] ["!" conversion] [":" format_spec] "}"
field_name        ::=  arg_name ("." attribute_name | "[" element_index "]")*
arg_name          ::=  [identifier | digit+]
attribute_name    ::=  identifier
element_index     ::=  digit+ | index_string
index_string      ::=  <any source character except "]"> +
conversion        ::=  "r" | "s" | "a"
format_spec       ::=  format-spec:format_spec

我們從第一行看起,第一行的內容為:

  • 結構 replacement_field 由以下幾個部分組成:
    1. 前綴 {
    2. 可選:結構 field_name
    3. 可選:
      1. 前綴!
      2. 結構 conversion
    4. 可選:
      1. 前綴:
      2. 結構 format_spec
    5. 後綴 }

而第二行的內容為:

  • 結構 field_name 由以下幾個部分組成:
    1. 結構 arg_name
    2. 任意個數的:
      • 二選一(其一):
        1. 前綴 .
        2. 結構 attribute_name
      • 二選一(其二):
        1. 前綴 [
        2. 結構 element_index
        3. 後綴 ]

這種表示方法和正則表達式很相似。| 表示或、[] 表示之間的內容可選、"" 表示之間的內容只是對應字符、而 ()* 表示中間的內容可以重複 0 至任意次。在倒數第三行,文檔在 <> 中間添加了一個注釋。

如果能直接讀懂這些內容,讀者就可以不依賴於文檔中的語言描述,直接解析語句的語法。這對於文檔中、語言描述不夠明確的情況時很好用。

延申:自定義格式化語法

編輯

根據上面的文檔,讀者還可以自行設置一套格式化語法和方式。具體讀懂上面的文檔,可能需要讀者學習之後的章節之後才能做到。

除上面的文檔外,還可以用 類的__format__方法 來自定義格式化語法。

f 字符串

編輯

f 字符串是一種創建字符串的方法。類似「原始字符串」在創建時就不進行轉義、「f字符串」在創建時就立即被格式化。

基本使用

編輯
value = "Python"
fstr1 = f"{value}"; print(fstr1)     #输出:Python
fstr2 = f"{value * 2}"; print(fstr2) #输出:PythonPython

f 字符串會把 {} 之間的內容,當成普通的 Python 表達式來求值,把表達式返回的結果轉換為字符串並輸出到原字符串內。

在使用表達式時,有以下注意事項:

  • 空表達式不被允許。
    比如 f"{}" 等,是不被允許的。
  • 可以使用注釋。
  • 表達式中不能出現作為運算符的 =

= 符號只要不作為賦值表達式而出現,也是可以在表達式中的。比如:

fstr3 = f"{ '= '* 3 }"
print(fstr3)  #输出:===

使用注釋

編輯

可以用以下方式使用注釋:

fstr = f"{1 + 2 #输出3}"
}"
print(fstr)  #输出:3

在注釋部分結束後,應當在下一行補一個 }"(或 }''' 等,取決於創建 f 字符串時使用的引號)。

= 標記(可選)

編輯

在表達式末尾,可以添加 =。此時,會在 f 字符串中同時輸出表達式的字符與表達式的結果。比如:

value = "Python"
fstr1 = f"{value =   }"
print(fstr1)
fstr2 = f"{value * 2=}"
print(fstr2)

輸出為:

value =   'Python'
value * 2='PythonPython'

等號前後以及表達式中的空格都會被原樣輸出。

! 轉換方式(可選)

編輯

= 標記的後面,可以設置把「表達式返回值」轉換為字符串的方式。具體有三種轉換方式:

  • !s(默認)用 str() 轉換。
  • !r(默認)用 repr() 轉換。
  • !a(默認)用 ascii() 轉換。

: 格式規格迷你語言

編輯

與 str.format 類似,這裡也可以使用格式規格迷你語言。在 str.format 中使用格式規格迷你語言的方法可以完全照搬到這裡。

但在 str.format 之外,這裡使用的格式規格迷你語言可以「按替換規則設置」。比如:

width = 6
precision = 4
value = 114.514
fstr = f"{value:@>{width}.{precision}}"
print(fstr)  输出:@114.5

在解析時,Python 先按規則替換 {width}{precision} 的內容,再替換 {value:@>6.4} 的內容。

轉義

編輯

特別的,{{ 會被替換為 {,而 }} 會被替換為 }。比如:

fstr = f"}} {{}} {1+2:$^{1+2}}"
print(fstr)

輸出為:

} {} $3$

如同上述示例,最後的 }} 分別與前面兩個單獨的 { 配對。如果有配對,就不會按轉義規則進行替換。

模板字符串

編輯


printf 式字符串格式化

編輯

這種方法很像是 C 語言中 printf 函數格式化字符串的方式。這種方法可處理的類型範圍較窄,並且更難以正確使用,但更為快速。

字符串的格式化運算

編輯

字符串和元組 / 字典之間支持一種特殊的二元運算:格式化運算,其運算符是%

示例:

s = "%(a)s %(b)s %(c)s"
d = {"a":"Py", "b":"th", "c":"on"}
print(s % d)  #输出:Py th on

s = "%s %s %s"
t = ("Py", "th","on")
print(s % t)  #输出:Py th on

被替換部分的規則

編輯

字符串中,被替換的部分由以下幾個部分組成:

部分 示例 解釋
% % 字符%

(可選)
(key_name) 用括號括起的、字典鍵的名稱。
轉換旗標
(可選)
此處列舉的旗標可以組合。
# 轉換數字時,使用「替代形式」(見「轉換類型」)
0 轉換數字時,用0填充
- 轉換值靠左對齊。如果同時給出旗標0,則覆蓋後者。
比如旗標-0等同於旗標-,而旗標0-等同於旗標0
(空格旗標)正數或空字符串前會留一個空格
+ 轉換數字時,前面一定有符號。
如果和空格旗標一起使用,此旗標產生的符號字符會覆蓋空格旗標的效果。
最小寬度
(可選)
* 由元組中、下一個元素的數值決定。
如果使用字典與字符串作格式化運算,則不能使用此項。
42 任意非負整數
精度
(可選)
.42 .開頭的、任意非負整數
.* 由元組中、下一個元素的數值決定。
如果使用字典與字符串作格式化運算,則不能使用此項。
長度修飾符
(可選)
h 長度修飾符可以為hlL
設置此項僅為了和 printf 函數一致,沒有任何作用。
轉換類型
(必須)
s 這裡給出的內容決定了內容轉換為字符串的方式。

轉換類型

編輯
轉換符 含意 替代形式
d 有符號十進制整數。
i 有符號十進制整數。
o 有符號八進制數。 0o開頭
u 過時類型 -- 等價於 d
x 有符號十六進制數(小寫)。 0x開頭
X 有符號十六進制數(大寫)。 0X開頭
e 浮點指數格式(小寫)。 (無論小數點後有沒有數值)
總是包含小數點。
E 浮點指數格式(大寫)。
f 浮點十進制格式。
小數點後的數碼位數由精度決定,默認為 6。
F 浮點十進制格式。
小數點後的數碼位數由精度決定,默認為 6。
g 浮點格式。
如果指數小於 -4 或不小於精度,則等同於e
否則,等同於f
末尾的零不會被移除。
(無論小數點後有沒有數值)
總是包含小數點。
G 浮點格式。
如果指數小於 -4 或不小於精度,則等同於E
否則,等同於F
c 單個字符(接受整數或單個字符的字符串)。
r repr()
如果指定精度,則輸出會被截短至精度
s str()
如果指定精度,則輸出會被截短至精度
a ascii()
如果指定精度,則輸出會被截短至精度
% 不轉換參數,在結果中輸出一個 % 字符。