用户: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()
如果指定精度,则输出会被截短至精度
% 不转换参数,在结果中输出一个 % 字符。