2.5. 字符串方法与格式化

字符串自带一套用于检视和重塑的内置方法工具箱。由于字符串是不可变的,每个方法都会返回一个 新的 字符串——原字符串保持不变。

2.5.1. 检视字符串

>>> name = "OpenMV Cam"
>>> name.startswith("Open")
True
>>> name.find("MV")
4
>>> name.count("m")
1
>>> "Cam" in name
True

2.5.2. 清理与大小写

>>> "  hello  ".strip()
'hello'
>>> "abc-123".replace("-", "_")
'abc_123'
>>> "OpenMV".lower()
'openmv'

2.5.3. 拆分与连接

  • str.split() —— 在每一处出现分隔符的地方把字符串拆分成一个列表(默认:任意连续的空白)。

  • str.join() —— 其逆操作:以接收者作为分隔符,把一个字符串序列拼接到一起。这是从各个片段构建一个长字符串的高效方式。

>>> "1,2,3".split(",")
['1', '2', '3']
>>> "hello world".split()
['hello', 'world']
>>> ", ".join(["a", "b", "c"])
'a, b, c'

2.5.4. f-string

将值插入字符串最简单的方式就是 f-string——一种带有 f 前缀的字符串字面量。{} 内的任何表达式都会被求值并插入:

>>> name = "OpenMV"
>>> count = 42
>>> f"{name} saw {count} blobs"
'OpenMV saw 42 blobs'

花括号内的冒号引入一个 格式说明符,用于控制值的呈现方式:

  • {x:.2f} —— 小数点后保留 2 位的浮点数。

  • {x:>10} —— 在宽度为 10 个字符的字段中右对齐。

  • {x:<10} —— 左对齐。

  • {x:0>4} —— 用前导零填充至宽度 4。

  • {x:#x} —— 带 0x 前缀的十六进制。

  • {x:b} —— 二进制表示。

>>> f"pi is roughly {3.14159:.3f}"
'pi is roughly 3.142'
>>> f"reg = {0xAB:#x}"
'reg = 0xab'
>>> for i in range(3):
...     print(f"line {i:0>3}")
line 000
line 001
line 002

在表达式名称后加上单个 = 会同时打印名称和值——便于快速调试打印:

>>> v = 3.14
>>> print(f"{v=}")
v=3.14

2.5.4.1. 整数进制转换

有三个内置函数完成与 :b / :o / :x 格式说明符相同的工作,但直接返回转换后的字符串:

  • bin() —— 二进制,带 "0b" 前缀。

  • oct() —— 八进制,带 "0o" 前缀。

  • hex() —— 十六进制,带 "0x" 前缀。

>>> hex(255)
'0xff'
>>> bin(10)
'0b1010'
>>> oct(8)
'0o10'

反方向——把一个 N 进制字符串转换回整数——使用带显式进制参数的 int 构造函数:

>>> int("ff", 16)
255
>>> int("0b1010", 2)         # the "0b" prefix is allowed
10

当你想要一个整数的原始字符串(用于日志行、配置文件、寄存器转储)时,请使用这些函数。当你需要填充、宽度,或想在同一个 f-string 中把值与其他文本混合时,请使用格式说明符。

2.5.5. 较旧的格式化风格

f-string 是推荐的风格,但另外两种较旧的方式仍然有效,并且会出现在现有代码中:

str.format() —— 在模板字符串上调用 .format() 方法,并传入位置参数或关键字参数,花括号作为占位:

>>> "Hello, {}".format(name)
'Hello, OpenMV'
>>> "{0} + {0} = {1}".format(2, 4)
'2 + 2 = 4'
>>> "{name}: {value}".format(name="frames", value=42)
'frames: 42'

格式说明符({:.2f}{:>10}、……)的工作方式与 f-string 中相同;唯一的区别在于值是 在哪里 提供的。

% 格式化(printf 风格)—— 单个 % 运算符把值替换到格式代码中,每个代码对应一个值。多个值以元组形式传入:

>>> "Hello, %s" % name
'Hello, OpenMV'
>>> "%d + %d = %d" % (2, 2, 4)
'2 + 2 = 4'
>>> "%.2f" % 3.14159
'3.14'

最常见的类型代码是 %s(字符串)、%d(整数)、%f(浮点数)和 %x(十六进制)。

每个 % 代码都可以在 % 与类型字母之间携带修饰符。完整形式是 %[flags][width][.precision]type

  • width(宽度)—— 字段必须占用的最少字符数。较短的值会用空格填充;较长的值会溢出。%10d 预留 10 个字符并使数字右对齐。

  • precision(精度)—— 含义取决于类型。对于浮点数,是小数点后的位数。%.2f 给出两位小数。对于字符串,是最多取用的字符数(%.5s 截断为五个字符)。

  • 左对齐 —— - 标志把字段放在左侧。%-10d 把数字放在左侧并在后面补空格。

  • 零填充 —— 0 标志用前导零代替空格进行填充(针对数值类型)。%05d 用零填充至五位。

  • 符号 —— + 标志始终显示数字的符号,正数也带上 +

  • 替代形式 —— # 标志。对于 %x,这会在输出前加上 0x 前缀;对于 %o,则加上 0o 前缀。

标志、宽度和精度可以组合使用:

>>> "%10d" % 42
'        42'                 # width 10, space-padded, right-aligned
>>> "%-10d|" % 42
'42        |'                # width 10, left-aligned
>>> "%05d" % 42
'00042'                      # width 5, zero-padded
>>> "%8.2f" % 3.14159
'    3.14'                   # width 8, 2 decimal places
>>> "%08.2f" % 3.14159
'00003.14'                   # width 8, zero-padded
>>> "%+d" % 42
'+42'                        # explicit sign
>>> "%#06x" % 0xAB
'0x00ab'                     # 0x prefix, zero-pad to 6 chars total

这两种较旧的风格都比 f-string 更难阅读、更容易出错——在新代码中请使用 f-string,并在阅读现有代码时认出这些较旧的形式。