字符串和编码
字符串(str)用来表示文本:姓名、文件名、网址、用户输入和日志消息都可以用字符串保存。Python 3 的字符串以 Unicode 字符为单位处理,因此中文、英文和表情可以统一操作;只有在和文件、网络通信时,才需要在字符串和字节之间进行编码转换。
学完本文后,你应该能够:
- 使用不同形式创建字符串,并正确处理引号和换行;
- 使用索引、切片和遍历读取字符串;
- 使用常用方法搜索、替换、拆分和拼接文本;
- 使用 f-string 生成可读的输出;
- 区分字符串(
str)和字节(bytes),处理 UTF-8 编码。
示例适用于 Python 3。字符串不可变,所有“修改字符串”的操作都会返回新字符串。
创建字符串
单引号和双引号没有类型上的区别,选择不与内容冲突的一种即可:
name = "小林"
message = '欢迎学习 Python'
quote = '他说:“开始吧。”'
apostrophe = "I'm learning Python."
字符串中同时出现两种引号时,可以使用反斜杠转义:
text = "他说:\"你好\""
path = "C:\\Users\\Alice"
原始字符串和多行字符串
原始字符串(前缀 r)让反斜杠大多按普通字符处理,适合正则表达式和 Windows 路径:
pattern = r"\d+\.\d+"
windows_path = r"C:\Users\Alice\notes.txt"
原始字符串不能以单个反斜杠结尾,例如 r"C:\" 是语法错误;可以再补一个反斜杠或使用 pathlib。
三引号可以创建多行字符串:
description = """这是第一行,
这是第二行。"""
三引号也常用于函数或模块的文档字符串(docstring):
def add(a, b):
"""返回两个数的和。"""
return a + b
长度、索引和切片
len() 返回字符串包含的字符数。索引从 0 开始,负数索引从末尾开始:
word = "Python"
print(len(word)) # 6
print(word[0]) # P
print(word[-1]) # n
索引必须在有效范围内,否则会抛出 IndexError。切片格式为 text[start:stop:step],包含 start,不包含 stop:
word = "Python"
print(word[0:2]) # Py
print(word[:2]) # Py,省略 start 表示从开头
print(word[2:]) # thon,省略 stop 表示到结尾
print(word[::2]) # Pto,每隔一个字符取一个
print(word[::-1]) # nohtyP,反向取值
切片的边界超出范围不会报错,而是自动截取可用部分:
print("abc"[0:99]) # abc
print("abc"[-99:2]) # ab
遍历和成员判断
字符串是可迭代对象,可以直接放进 for:
for character in "Python":
print(character)
使用 in 和 not in 判断子字符串是否出现:
email = "student@example.com"
print("@" in email) # True
print(".org" not in email) # True
in 判断的是连续子串,不是任意字符集合。例如,"py" in "Python" 为 False,因为大小写不同。
字符串不可变
字符串创建后不能按索引直接修改:
word = "Python"
# word[0] = "J" # TypeError
需要得到新文本时,使用切片、拼接或方法:
word = "Python"
word = "J" + word[1:]
print(word) # Jython
频繁使用 + 拼接大量片段效率较低,通常先收集片段,再用 str.join() 一次拼接。
常用字符串方法
字符串方法不会改变原字符串,而是返回结果:
raw = " Python 入门 "
print(raw.strip()) # Python 入门,去除两端空白
print(raw.lstrip()) # 去除左侧空白
print(raw.rstrip()) # 去除右侧空白
print(raw.lower()) # 转小写(中文不受影响)
print(raw.upper()) # 转大写
print(raw.replace("入门", "基础")) # 替换子串
查找和统计
text = "banana"
print(text.find("na")) # 2,找不到时返回 -1
print(text.index("na")) # 2,找不到时抛出 ValueError
print(text.count("a")) # 3
print(text.startswith("ba")) # True
print(text.endswith("na")) # True
不确定子串是否存在时,优先使用 find() 或 in;index() 适用于“找不到就是程序错误”的场景。
拆分和拼接
split() 把字符串拆成列表,join() 把多个字符串连接起来:
csv_line = "Python,Java,Go"
languages = csv_line.split(",")
print(languages) # ['Python', 'Java', 'Go']
result = " / ".join(languages)
print(result) # Python / Java / Go
不传参数时,split() 会按连续空白拆分,并忽略两端空白:
words = " learn Python ".split()
print(words) # ['learn', 'Python']
判断内容类型
isalpha()、isdigit()、isalnum() 等方法可用于简单校验:
print("Python".isalpha()) # True
print("123".isdigit()) # True
print("A12".isalnum()) # True
print(" ".isspace()) # True
这些方法只判断字符组成,不负责完整验证。例如电话号码、邮箱和身份证号仍需要更明确的规则。
字符串格式化
推荐使用 f-string:在字符串前加 f,把表达式写在 {} 中:
name = "小林"
score = 92.567
print(f"{name} 的成绩是 {score:.1f} 分")
# 小林 的成绩是 92.6 分
常用格式说明符:
number = 42
price = 19.9
print(f"编号:{number:04d}") # 编号:0042
print(f"价格:{price:.2f}") # 价格:19.90
print(f"百分比:{0.875:.1%}") # 百分比:87.5%
大括号本身需要写成 {{ 和 }}:
print(f"{{name}} = {name}") # {name} = 小林
旧代码中还可能见到 str.format() 和 % 格式化。它们仍可用,但新代码通常优先选择更直观的 f-string。
Unicode、编码和字节
字符是人类看到的文字,编码是把字符映射为字节的规则。Unicode 为字符分配统一的码点;UTF-8、UTF-16 等是把码点编码为字节的方式。
Python 的 str 保存 Unicode 文本:
text = "你好,Python"
print(type(text)) # <class 'str'>
与文件或网络传输时,使用 encode() 把字符串变成 bytes,使用 decode() 还原:
text = "你好"
data = text.encode("utf-8")
print(data) # b'\xe4\xbd\xa0\xe5\xa5\xbd'
restored = data.decode("utf-8")
print(restored) # 你好
编码和解码必须使用相同的字符集,否则可能抛出 UnicodeDecodeError 或出现乱码:
# data.decode("gbk") # 不应随意使用与实际数据不符的编码
读写文本文件时,显式指定编码最稳妥:
from pathlib import Path
path = Path("notes.txt")
path.write_text("第一行\n第二行", encoding="utf-8")
content = path.read_text(encoding="utf-8")
print(content)
bytes 适合图片、压缩包和网络报文等原始数据,不能直接与 str 拼接:
text = "版本:"
data = b"3.12"
# print(text + data) # TypeError
print(text + data.decode("ascii"))
常见错误
忘记字符串不可变
strip()、replace() 等方法不会就地修改变量,需要接收返回值:
name = " Alice "
name.strip()
print(name) # 仍然是 " Alice "
name = name.strip()
把字符数和字节数混为一谈
text = "你好"
print(len(text)) # 2,字符数
print(len(text.encode("utf-8"))) # 6,UTF-8 字节数
用 split() 解析复杂格式
简单分隔文本可以使用 split();CSV 中如果字段本身包含逗号或引号,应使用标准库 csv,不要手写完整解析器。
综合示例:统计一段文本
text = "Python is simple. Python is useful."
normalized = text.lower().replace(".", "")
words = normalized.split()
print(f"单词数:{len(words)}")
print(f"Python 出现次数:{words.count('python')}")
print(" / ".join(words))
处理文本时,可以按“清理—拆分—统计/转换—输出”的顺序组织步骤。每一步都产生清晰的中间结果,便于调试。
练习
- 输入一行姓名,去除两端空白后输出“你好,姓名!”。
- 给定
"red,green,blue",拆分成列表,再用" | "拼接回来。 - 统计一段英文中不区分大小写的单词
python出现了多少次。 - 把字符串
"价格:19.9"中的数字转换为浮点数,并格式化为两位小数。 - 将
"学习 Python"编码为 UTF-8,再解码回字符串,观察str和bytes的类型差异。
小结
str表示 Unicode 文本,字符串支持索引、切片、遍历和成员判断。- 字符串不可变,方法和拼接会返回新字符串。
split()、join()、replace()、find()、strip()是处理文本的常用工具。- f-string 适合把变量和格式说明组合到输出中。
- Unicode 解决“字符是什么”,UTF-8 等编码解决“字符如何变成字节”;
encode()和decode()负责两者转换。 - 文件和网络边界应明确指定编码,
bytes不应直接当作str使用。