🎯 学习目标
- 理解字符串的不可变性与 Unicode 本质
- 熟练掌握索引与切片(含逆序、步长)
- 系统掌握字符串 30+ 常用方法,能按场景选择
- 掌握三种格式化方式,重点精通 f-string
- 理解字符编码(ASCII/Unicode/UTF-8)与乱码成因
- 会用
encode/decode、原始字符串、转义字符
1字符串的创建与本质
s1 = '单引号'
s2 = "双引号"
s3 = """三引号支持
跨行字符串,换行和缩进都会保留"""
s4 = '''同样可以用三个单引号'''
empty = "" # 空字符串
ch = "A" # 单字符也是 str,没有 char 类型
# 构造
str(123) # '123'
str([1, 2]) # '[1, 2]'
# 字符串是【不可变】序列:创建后内容不能修改
s = "abc"
# s[0] = "x" # TypeError!不能原地修改
s = "x" + s[1:] # 只能拼接出新字符串
print(s) # xbc
2索引:按位置取字符
字符串中每个字符都有编号,从 0 开始;Python 还支持负索引,从末尾倒数(-1 是最后一个):
字符串: P y t h o n
正索引: 0 1 2 3 4 5
负索引: -6 -5 -4 -3 -2 -1
s = "Python"
print(s[0]) # P
print(s[-1]) # n(最后一个,最常用)
print(s[-2]) # o
# print(s[10]) # IndexError:越界报错(与切片不同)
3切片:取子串的万能语法
切片是 Python 最优雅的语法之一,格式为 s[start:stop:step],记忆口诀"含头不含尾,省略取到头":
s = "0123456789"
s[2:5] # '234' 下标 2、3、4(不含5)
s[:4] # '0123' 从头开始到下标3
s[6:] # '6789' 下标6到末尾
s[:] # 完整复制(浅拷贝)
s[::2] # '02468' 每隔一个取(步长2)
s[1:8:2] # '1357'
s[::-1] # '9876543210' 字符串逆序!经典写法
s[-3:] # '789' 取最后3个字符
s[:-3] # '0123456'去掉最后3个字符
s[8:2:-1] # '876543' 反向切片:从8取到3(不含2)
# 切片【永不报越界错】,自动收敛到有效范围
s[5:100] # '56789'
切片同样适用于列表、元组等所有序列类型,一次学会处处可用。NLP 中取前后缀、文本截断、反转都靠它。
4运算:拼接、重复、成员、长度
"a" + "b" # 'ab' 拼接
"ab" * 3 # 'ababab' 重复
len("你好python") # 8 长度(按字符数,不是字节数)
"yth" in "python" # True 子串判断
"xyz" not in "python" # True
max("abc") # 'c' 按码点取最大
sorted("cab") # ['a','b','c'] 返回排序后的列表
循环中用 + 反复拼接大量字符串效率很低(每次都生成新对象)。正确做法是先把子串放入列表,最后用 "".join(list) 一次合并。
# 高效拼接
parts = ["2026", "10", "25"]
date = "-".join(parts) # '2026-10-25'
# 字符与码点
ord("中") # 20013(Unicode 码点)
chr(20013) # '中'
5字符串方法大全
字符串方法极多且都不修改原字符串(不可变),而是返回新字符串。按用途分类如下。
5.1 查找与统计
| 方法 | 作用 | 示例 |
|---|---|---|
find(sub) | 返回首次出现的下标,找不到返回 -1 | "abcab".find("ab") → 0 |
rfind(sub) | 从右侧找,返回下标 | "abcab".rfind("ab") → 3 |
index(sub) | 同 find,但找不到抛异常 | "abc".index("b") → 1 |
count(sub) | 统计子串出现次数 | "aabaa".count("a") → 4 |
startswith(s) | 是否以某串开头 | "report.pdf".startswith("report") |
endswith(s) | 是否以某串结尾(判断扩展名神器) | "a.py".endswith(".py") → True |
filename = "photo_2026.png"
if filename.endswith((".png", ".jpg", ".jpeg")): # 可传元组匹配多个
print("这是图片文件")
5.2 大小写转换
s = "Hello World"
s.upper() # 'HELLO WORLD'
s.lower() # 'hello world' 英文统一比较时先 lower
s.title() # 'Hello World' 每个单词首字母大写
s.capitalize() # 'Hello world' 整句首字母大写
s.swapcase() # 'hELLO wORLD' 大小写互换
" abc ".strip().upper() # 'ABC' 可链式调用
# 判断类(返回 bool)
"abc123".isalnum() # True 全是字母或数字
"abc".isalpha() # True 全是字母
"123".isdigit() # True 全是数字
" ".isspace() # True 全是空白
"Hello".istitle() # True
"ABC".isupper() # True
5.3 清洗:strip / replace / translate
" hello \n".strip() # 'hello' 去掉两端空白(空格/\t/\n)
"xxhelloxx".strip("x") # 'hello' 去掉两端指定字符集合
" hi ".lstrip() # 'hi ' 只去左侧
" hi ".rstrip() # ' hi' 只去右侧
"I like Java".replace("Java", "Python") # 'I like Python' 全部替换
"aaaa".replace("a", "b", 2) # 'bbaa' 只替换前2次
# NLP 数据清洗常用:批量替换多种字符
table = str.maketrans({",": ",", "。": ".", "!": "!"})
"你好,世界!".translate(table) # '你好,世界!'
strip("abc") 去掉的是"由 a/b/c 任意排列组成的两端字符",不是去掉子串 "abc"!要删子串请用 replace("abc", "")。
5.4 分割与合并(NLP 高频)
# split:字符串 → 列表
"a,b,c".split(",") # ['a', 'b', 'c']
"2026-10-25".split("-") # ['2026', '10', '25']
"a b c".split() # ['a','b','c'] 不带参数时按任意空白分割(自动合并连续空白)
"a,b,c".split(",", 1) # ['a', 'b,c'] 最多分割1次
"line1\nline2".splitlines() # ['line1', 'line2'] 按行分割
# partition:分割一次且保留分隔符,返回三元组
"localhost:8080".partition(":") # ('localhost', ':', '8080')
# join:列表 → 字符串(split 的逆操作)
"-".join(["2026", "10", "25"]) # '2026-10-25'
"".join(["P", "y", "thon"]) # 'Python'
",".join(str(i) for i in [1, 2, 3]) # '1,2,3'(元素必须是字符串)
5.5 对齐与填充
"42".center(6) # ' 42 ' 居中到宽度6
"42".zfill(6) # '000042' 左侧补0(处理编号常用)
"hi".ljust(6, "-") # 'hi----'
"hi".rjust(6, "*") # '****hi'
5.6 判断与转换的 is* 家族
# 识别字符串包含的字符类别(中文场景)
"中文".isalpha() # True!汉字也被视为字母
"123".isdigit() # True!全角数字也算
"Ⅲ".isdigit() # True!罗马数字也算
"⅔".isnumeric() # True!分数也算
# 需要严格"ASCII 阿拉伯数字"时:
s = "123"
print(s.isascii() and s.isdigit()) # True
6字符串格式化
6.1 f-string(Python 3.6+,最推荐)
name, score = "小明", 95.468
# 基本插值:变量、表达式、函数调用都能放 {} 里
f"{name} 的成绩是 {score}" # '小明 的成绩是 95.468'
f"{1 + 2}" # '3'
f"{name.upper()}" # '小明'
# 格式说明符:{值:格式}
f"{score:.2f}" # '95.47' 保留2位小数
f"{score:+.2f}" # '+95.47' 带正负号
f"{0.25:.1%}" # '25.0%' 百分比
f"{255:0>4d}" # '0255' 宽度4,右对齐补0
f"{255:b}" / f"{255:x}" / f"{255:o}" # '11111111' / 'ff' / '377'
f"{3.14:<10}|" # '3.14 |' 左对齐宽10
f"{3.14:^10}" # 居中
# 千分位(财务报表常用)
f"{1234567:,}" # '1,234,567'
# 日期
from datetime import datetime
f"{datetime(2026,10,25):%Y年%m月%d日}" # '2026年10月25日'
# Python 3.8+:= 说明符,连变量名一起输出(调试神器)
x = 42
print(f"{x=}") # 'x=42'
6.2 str.format()
"{}今年{}岁".format("小明", 18) # 按位置
"{0}-{1}-{0}".format("a", "b") # 'a-b-a' 可重复引用
"{name}={score}".format(name="语文", score=90)
"{:>10.2f}".format(3.14) # ' 3.14'
6.3 % 旧式格式化(老代码常见,能读懂即可)
"%s今年%d岁" % ("小明", 18) # %s 字符串 %d 整数 %f 浮点
"价格:%.2f" % 9.9 # '价格:9.90'
"%5d|%-5d|" % (42, 42) # 右对齐 / 左对齐
7转义字符与原始字符串
| 转义 | 含义 | 转义 | 含义 |
|---|---|---|---|
\n | 换行 | \\ | 反斜杠本身 |
\t | 制表符 Tab | \' | 单引号 |
\r | 回车 | \" | 双引号 |
\b | 退格 | \u4e2d | Unicode 字符(中) |
print("第一行\n第二行")
print("他说:\"你好\"") # 他说:"你好"
print("路径:C:\\Users\\name") # 每个反斜杠要写两遍 —— 很丑
# 原始字符串 r"...":反斜杠一律不转义(文件路径、正则表达式必备)
path = r"C:\Users\name\Desktop\report.txt"
import re
re.findall(r"\d+", "a12b34") # 正则一律加 r 前缀
8字符编码:彻底搞懂中文乱码
8.1 发展脉络
- ASCII:美国人制定,128 个字符(英文字母、数字、符号),1 字节足够,但没有中文。
- GB2312 / GBK:中国的中文编码(GBK 兼容 GB2312,收录 2 万多汉字),Windows 中文版默认代码页 936。
- Unicode:全球统一字符集,给世界上每个字符一个唯一编号(码点),如"中"= U+4E2D。但它只规定编号,没规定怎么存。
- UTF-8:Unicode 的一种存储实现(变长 1~4 字节),英文 1 字节、汉字通常 3 字节,是互联网与工程的事实标准。
乱码的唯一原因:用错误的编码去解码。 文件按 GBK 存的字节,却按 UTF-8 解读,必然乱码。记住"用什么编码写,就用什么编码读"。现代项目一律使用 UTF-8。
8.2 str 与 bytes 的转换
# str(人看的文本) ⇄ bytes(机器存的字节)
s = "中文Python"
# 编码 encode:字符串 → 字节
b_utf8 = s.encode("utf-8")
b_gbk = s.encode("gbk")
print(b_utf8) # b'\xe4\xb8\xad\xe6\x96\x87Python'
print(len(b_utf8)) # 12 (2个汉字×3 + 6个英文 = 12 字节)
print(len(b_gbk)) # 10 (2个汉字×2 + 6 = 10 字节)
print(len(s)) # 8 (字符数)
# 解码 decode:字节 → 字符串(必须用相同编码!)
print(b_utf8.decode("utf-8")) # 中文Python
# print(b_utf8.decode("gbk")) # UnicodeDecodeError 或乱码
# 字节字面量
b = b"hello" # ASCII 内容可直接 b 前缀书写
8.3 文件读写中的编码
# Windows 上 open 默认编码是 GBK(cp936)!读写中文文件务必显式指定 utf-8
with open("data.txt", "w", encoding="utf-8") as f:
f.write("中文内容")
with open("data.txt", "r", encoding="utf-8") as f:
print(f.read())
# 网页 requests 取到响应但编码猜错时:
# resp.encoding = "utf-8" 或 resp.apparent_encoding 自动探测
9综合案例:文本信息统计
text = """Python is powerful. Python is easy.
学习 Python 很有趣!"""
# 1) 词频(简单按空格,中文分词请看 NLP 篇第3章 jieba)
words = text.lower().replace(".", "").replace("!", "").split()
freq = {}
for w in words:
freq[w] = freq.get(w, 0) + 1
print(freq) # {'python': 2, 'is': 2, 'powerful': 1, ...}
# 2) 字符统计
total = len(text.replace("\n", ""))
chinese = sum(1 for ch in text if '\u4e00' <= ch <= '\u9fff') # 统计汉字
print(f"总字符 {total},其中汉字 {chinese} 个")
# 3) 脱敏:保留首尾字符,中间用 * 代替
phone = "13812345678"
masked = phone[:3] + "*" * (len(phone) - 7) + phone[-4:]
print(masked) # 138****5678
10本章小结与练习
📌 关键结论
- 字符串是不可变的 Unicode 序列,所有方法都返回新串。
- 切片
s[起:止:步长]含头不含尾、永不越界;[::-1]逆序。 - 清洗三件套:
strip / replace / split+join;判断扩展名用endswith。 - 格式化首选 f-string,
:.2f、:,、:0>4d最常用。 - 路径与正则用
r"";文件读写显式写encoding="utf-8"。
练习1:s = "Hello,Python世界",如何取出最后4个字符、逆序、统计字母 o 的个数?
最后4个字符 s[-4:];逆序 s[::-1];统计 s.count("o")。注意 len 按字符计,中文每个字算 1 个字符。
练习2:把字符串 "a,,b,,,c" 清理成列表 ['a','b','c']。
直接 split(",") 会产生空串:['a','','b','','','c']。应过滤空值:
[x for x in "a,,b,,,c".split(",") if x];也可用正则 re.split(r",+", s)。练习3:把 " I Love Python " 变成规范的 "I love python"(去空白、除首词外小写)。
words = s.strip().split(); words[0] + " " + " ".join(w.lower() for w in words[1:])。考察 strip、无参 split 合并多余空格、join 组合。