3 字符串、切片、二进制列和正则表达式

皮皮罴 / 2024-02-06 / 原文

字符串

形式

字符串一般被单引号''(可以内嵌双引号)、双引号""(可以内嵌单引号)、三重引号(多行,与多行注释的格式一致)包围,并使用\作为转义字符。


切片

用法

包括字符串、列表、元组在内的多个有序可迭代数据类型都支持切片运算。iters[i:j:k]表示可迭代对象下标从ij - 1的步长为k的子列(:k可以省略,默认为\(1\)),即遵循左闭右开的原则。
ijk可以是一切整数,即使其小于\(0\),或者大于len(iters)。同时,i可以大于等于j。考虑\(k > 0\)时:

  1. \(i \ge j\)时,切片为空。
  2. \(i \ge len(iters)\)时,切片为空。
  3. \(j \gt len(iters)\)时,切片的有效右边界为len(iters)
  4. \(i\)\(j\)为负数时,对应表示的下标将从可迭代对象的右侧开始计数,例如iters[-1]表示最后一个元素,iters[-2]表示倒数第二个元素。
  5. \(i\)省略时,默认i = 0;当\(j\)省略时,默认j = len(iters)
letters = 'python'
arrays = [1, 2, 3, 4, 5]

print(letters[1:2])  # y
print(letters[3:8])  # hon,不会报错,但是右边界为6。
print(letters[2:2])  # ``,不会报错,但输出为空。
print(letters[7:10]) # ``,不会报错,但输出为空。

print(arrays[:])     # [1, 2, 3, 4, 5],可以作为复制对象的方式。
print(arrays[1:])    # [2, 3, 4, 5]
print(arrays[:-1])   # [1, 2, 3, 4]
print(arrays[-4:-2]) # [2, 3]
print(arrays[:-9])   # []

\(k<0\)时,表示倒序的步长。

arrays = [1, 2, 3, 4, 5]
print(arrays[::-1]) # [5, 4, 3, 2, 1],可以作为获取倒序对象的方式。

注意点

切片是对原对象的一次“拷贝”,与直接赋值不同(直接将对象的头地址提供给新变量),切片将某一段值“复制”下来并申请的内存空间来存储。因此在切片上修改非引用对象不会导致原对象的修改,在原对象上修改非引用对象也不会导致已有的切片的值。

既然切片是浅拷贝,则说明切片仅仅复制了父对象,对于父对象下的一干子对象都没有复制:

arrays = [1, 2, 3, 4]
lines = ['abcde', arrays, 17, 18] # lines父对象中包含了arrays子对象。
result = lines[1:] # 根据浅拷贝的定义,切片与原对象对arrays的引用仍然是同一个。

print(result) # [[1, 2, 3, 4], 17, 18]
# 对切片中非引用对象的修改只修改了切片,没有修改到原对象。
result.append(19)
print(lines)  # ['abcde', [1, 2, 3, 4], 17, 18]
print(result) # [[1, 2, 3, 4], 17, 18, 19]
# 对切片中引用对象的修改涉及到了子对象arrays,浅拷贝并没有拷贝arrays。
arrays.append(5)
print(lines)  # ['abcde', [1, 2, 3, 4, 5], 17, 18],导致了原对象的修改。
print(result) # [[1, 2, 3, 4, 5], 17, 18, 19]

运算

字符串的运算支持加法和乘法,表示“连接”和“重复”。

letters1, letters2 = 'abcde', 'fgh'
print(letters1 + letters2) # abcdefgh
print(letters1 * 2)        # abcdeabcde

此外有r表达式,表示不做任何处理的字符串:

letters1, letters2, letters3 = r'a\b\c\naa', 'a\b\c\naa', 'a\\b\\c\\naa'
print(letters1) # a\b\c\naa
# letters2被转义:\b->退格,\n->换行,同时由于\c无法转义会抛出警告。
print(letters2) # \c[换行]aa
print(letters3) # a\b\c\naa

方法

见Python文档。

格式化

Python现版本提供3种常用的字符串格式化方法。

通过%实现格式化

`'%s%%%d' % ('CyberPunk', 2077)` # CyberPunk%2077

通过%?的形式来实现占位符,并以元组的方式顺序表示被格式化的字符串。常见的%?有:

表示 含义
%s 字符串
%d 整数
%u 无符号整数
%o 无符号八进制数
%x 无符号十六进制数
%f 浮点数
%e 科学计数法表示的浮点数
%p 十六进制格式的地址
%% %

通过.format()方法实现格式化

str.format(*args, **kwargs)
'''
执行字符串格式化操作。
调用此方法的字符串可以包含字符串字面值或者以{}括起来的替换域。每个替换域可以包含一个位置参数
的数字索引,或者一个关键字参数的名称。
:return: 字符串副本中每个替换域都会被替换为对应参数的字符串值。
'''

# 使用:
# 以下全部输出CyberPunk 2077。
'Cyber{} {}'.format('Punk', 2077)
'Cyber{1} {0}'.format(2077, 'Punk')
'Cyber{name} {year}'.format(name = 'Punk', year = 2077)
# 此外,可以使用不定长参数的形式向.format()中传递参数。
'Cyber{} {}'.format(*('Punk', 2077))

通过.format()实现数字的格式化:

# 含符号位保留2位小数
'{:.2f}'.format(3.1415926) # 3.14
# 左边补x,宽度为4
'{:x>4d}'.format(314)      # x314
# 右边补x,宽度为4
'{:x<4d}'.format(159)      # 159x
# {:,}采用逗号,分隔
'{:,}'.format(31415926)    # 31,415,926
# {:.n%}n位小数百分比计数
'{:.2%}'.format(0.314)     # 31.40%
# {:.ne}n位小数指数计数
'{:.2e}'.format(314159)    # 3.14e+05
# {:>nd}n位右对齐、{:<nd}n位左对齐、{:^nd}居中
'{:>10d}'.format(314)      #        314
'{:<10d}'.format(314)      # 314
'{:^10d}'.format(314)      #    314

通过F表达式格式化字符串

F表达式形如f'',在引号中包含被花括号包围的变量名称。

arrays = ['Punk', 2077]
print(f'Cyber{arrays[0]} {arrays[1]}') # CyberPunk 2077
print(f'{arrays[1] + 1 = }') # arrays[1] + 1 = 2078,通过=拼接运算结果。

二进制列bytes

正则表达式re