Python: 字符串基础
编程中打交道最多的数据类型不是数字,而是文本。用户名、邮箱、文章内容、JSON 数据、网页 HTML……全是字符串。这一课系统学习 Python 中字符串的各种操作。
1. 字符串的三种引号
Python 允许用三种方式定义字符串:
# 单引号
s1 = 'Hello'
# 双引号
s2 = "Hello"
# 三引号(多行字符串)
s3 = """这是第一行
这是第二行
这是第三行"""
单引号和双引号没有区别,选一种保持一致就好:
# 以下两种写法等价
name = 'Charlie'
name = "Charlie"
但如果你需要在字符串中包含引号本身,就需要混合使用:
# 字符串里有单引号,外面用双引号
text = "It's a beautiful day"
print(text) # It's a beautiful day
# 字符串里有双引号,外面用单引号
text = '他说:"你好!"'
print(text) # 他说:"你好!"
# 或者用转义符(不推荐,可读性差)
text = 'It\'s a beautiful day'
(1) 三引号:多行文本的好帮手
三引号(""" 或 ''')可以保留文本的换行和格式:
# 用三引号写多行文本
message = """尊敬的顾客,您好!
感谢您选择我们的服务。您的订单已确认。
预计送达时间:3 个工作日内。
如有疑问,请联系客服。
祝您生活愉快!"""
print(message)
运行结果:
尊敬的顾客,您好!
感谢您选择我们的服务。您的订单已确认。
预计送达时间:3 个工作日内。
如有疑问,请联系客服。
祝您生活愉快!
三引号常用于:长文本、文档注释、函数说明。
2. 转义字符
有些字符不能直接在字符串里写(比如换行、制表符、引号本身),需要用转义字符来表示——在字符前面加一个反斜杠 \。
| 转义符 | 含义 |
|---|---|
\n |
换行 |
\t |
制表符(Tab) |
\\ |
反斜杠本身 |
\' |
单引号 |
\" |
双引号 |
print("第一行\n第二行") # \n 换行
print("姓名:Alice\t年龄:25岁") # \t 制表符对齐
print("C:\\Users\\Charlie\\桌面") # \\ 输出反斜杠
print("他说:\"你好!\"") # \" 双引号
运行结果:
第一行
第二行
姓名:Alice 年龄:25岁
C:\Users\Charlie\桌面
他说:"你好!"
▶ 示例:格式化输出表格(难度⭐)
# 用 \t 对齐输出表格
print("商品\t单价\t数量\t总价")
print("------------------------")
print("苹果\t5.0\t3\t15.0")
print("香蕉\t3.5\t5\t17.5")
print("牛奶\t12.0\t2\t24.0")
运行结果:
商品 单价 数量 总价
------------------------
苹果 5.0 3 15.0
香蕉 3.5 5 17.5
牛奶 12.0 2 24.0
\t 常用于对齐文本,但如果内容长度不一,对齐效果可能不完美。正式场景建议用 f-string 的格式控制({value:10} 表示占用 10 个字符宽度)。
3. 原始字符串
如果你写过 Windows 文件路径,一定遇到过这样的痛苦:
# 糟糕!\n 被解释成了换行
path = "C:\Users\new_folder\documents"
print(path)
# 输出:C:\Users
# ew_folder\documents
解决办法:在字符串前面加 r,告诉 Python"不要处理转义符,原样输出":
# ✅ 原始字符串——r 前缀
path = r"C:\Users\new_folder\documents"
print(path)
# 输出:C:\Users\new_folder\documents
原始字符串(raw string)中的每个字符都是它自己,\n 不再表示换行,\t 不再表示制表符。
# 正则表达式中的原始字符串(后面会用到)
pattern = r"\d{3}-\d{8}" # 匹配电话号码:010-12345678
# 文件路径
log_path = r"D:\logs\app\2026\06\error.log"
print(f"日志路径:{log_path}")
r"abc\" 会报错。因为 \" 虽然不被当成转义符处理,但 Python 解析器会认为引号被转义了,导致字符串没有正常结束。
4. 字符串索引
字符串是由字符组成的序列,每个字符都有一个位置(索引)。Python 的索引从 0 开始:
text = "Python"
# 索引:0→P 1→y 2→t 3→h 4→o 5→n
print(text[0]) # P
print(text[1]) # y
print(text[5]) # n
Python 还支持负数索引,从右往左数,-1 是最后一个字符:
text = "Python"
print(text[-1]) # n(倒数第1个)
print(text[-2]) # o(倒数第2个)
print(text[-3]) # h
print(text[-6]) # P(倒数第6个,就是第一个)
(1) 索引示意图
正索引: 0 1 2 3 4 5
┌────┬────┬────┬────┬────┬────┐
│ P │ y │ t │ h │ o │ n │
└────┴────┴────┴────┴────┴────┘
负索引: -6 -5 -4 -3 -2 -1
▶ 示例:提取字符信息(难度⭐)
# 从身份证号中提取基本信息
id_number = "110101199001011234"
# 前6位:地址码
address_code = id_number[:6] # 切片的写法后面会讲
print(f"地址码:{address_code}")
# 第7-14位:出生日期
birth = id_number[6:14]
year = birth[:4]
month = birth[4:6]
day = birth[6:8]
print(f"出生日期:{year}年{month}月{day}日")
# 最后一位(-1):校验码
last_digit = id_number[-1]
print(f"校验码:{last_digit}")
运行结果:
地址码:110101
出生日期:1990年01月01日
校验码:4
string[6:14] 这种写法叫做切片(slicing),下面马上讲到。
5. 字符串切片
切片就是从字符串中取出一段子串。语法:字符串[起点:终点:步长]
text = "Hello, Python!"
# 基本切片:起点:终点(不包括终点)
print(text[0:5]) # Hello(第0到第4个字符)
print(text[7:13]) # Python(第7到第12个字符)
(1) 省略写法
text = "Hello, Python!"
print(text[:5]) # Hello——省略起点,从开头到索引5
print(text[7:]) # Python!——省略终点,从索引7到结尾
print(text[:]) # Hello, Python!——全部
(2) 步长
text = "Hello, Python!"
print(text[::2]) # Hlo yhn!——每2个取1个
print(text[1::2]) # el,Pto——从索引1开始每2个取1个
(3) 负数步长(反转)
text = "Hello, Python!"
print(text[::-1]) # !nohtyP ,olleH——反转整个字符串!
print(text[5:0:-1]) # ,olle——从索引5到0,反向取
(4) 切片示例
# 实用的切片技巧
url = "https://www.example.com"
# 去掉协议头
without_https = url[8:] # www.example.com
print(without_https)
# 获取域名
domain = url[8:-4] # www.example
print(domain)
# 反转字符串
name = "上海自来水来自海上"
reversed_name = name[::-1] # 上海自来水来自海上(回文)
print(name == reversed_name) # True——是回文!
# 每隔一个字符取一个
code = "H1e2l3l4o5"
clean = code[::2] # Hello
print(clean)
运行结果:
www.example.com
www.example
True
Hello
[::-1] 是 Python 中反转字符串的经典写法,简单又优雅。但注意:切片永远不会报 IndexError——即使起点或终点超出了字符串长度,Python 也会安全地返回它能取到的内容。
6. 常用字符串方法
字符串有很多内置方法,这里先学最常用的几个。不需要全记——知道有这些功能就行,用多了自然记得住。
(1) 大小写转换
text = "Hello, Python!"
print(text.upper()) # HELLO, PYTHON!
print(text.lower()) # hello, python!
print(text.title()) # Hello, Python!
print(text.capitalize()) # Hello, python!
(2) 去除空白
text = " Hello, World! "
print(f"|{text}|") # | Hello, World! |
print(f"|{text.strip()}|") # |Hello, World!|——去掉两端
print(f"|{text.lstrip()}|") # |Hello, World! |——去掉左边
print(f"|{text.rstrip()}|") # | Hello, World!|——去掉右边
(3) 查找和替换
text = "Hello, Python! Python is fun!"
print(text.find("Python")) # 7——第一次出现的位置
print(text.find("Java")) # -1——没找到返回 -1
print(text.count("Python")) # 2——出现次数
new_text = text.replace("Python", "Java")
print(new_text) # Hello, Java! Java is fun!
# replace 可以指定替换次数
partial = text.replace("Python", "Java", 1)
print(partial) # Hello, Java! Python is fun!
(4) 判断类方法
print("hello".isalpha()) # True——全是字母
print("hello123".isalpha()) # False——有数字
print("12345".isdigit()) # True——全是数字
print("hello123".isalnum()) # True——字母+数字
print("hello!".isalnum()) # False——有感叹号
print(" ".isspace()) # True——全是空白
if user_input.isdigit(): 可以确保 int() 转换不会出错。
(5) 拆分与合并
# split():字符串 → 列表
sentence = "I love Python"
words = sentence.split()
print(words) # ['I', 'love', 'Python']
# 指定分隔符
csv_line = "Alice,25,北京"
fields = csv_line.split(",")
print(fields) # ['Alice', '25', '北京']
# join():列表 → 字符串
parts = ["2026", "06", "23"]
date = "-".join(parts)
print(date) # 2026-06-23
▶ 示例:数据清洗(难度⭐⭐)
# 模拟用户输入的脏数据
raw_data = " Alice , 25 , 北京 \n"
# 清洗流程
# 1. strip() 去掉首尾空白
cleaned = raw_data.strip()
print(f"步骤1:|{cleaned}|")
# 2. split() 按逗号拆分
fields = cleaned.split(",")
print(f"步骤2:{fields}")
# 3. 每个字段再去掉多余空格
name = fields[0].strip()
age = fields[1].strip()
city = fields[2].strip()
print(f"姓名:{name}")
print(f"年龄:{age}")
print(f"城市:{city}")
运行结果:
步骤1:|Alice , 25 , 北京|
步骤2:['Alice ', ' 25 ', ' 北京']
姓名:Alice
年龄:25
城市:北京
7. len():获取字符串长度
len() 是 Python 内置函数,用来获取字符串(以及其他序列)的长度:
text = "Hello, Python!"
print(len(text)) # 15
# 中文字符每个算 1 个长度
chinese = "你好,世界!"
print(len(chinese)) # 6
# 空字符串长度为 0
print(len("")) # 0
# 常用场景:限制输入长度
username = "Charlie同学"
if len(username) < 2:
print("用户名太短")
elif len(username) > 10:
print("用户名太长")
else:
print(f"用户名 {username} 长度合格")
len("中") 的结果是 1,不是 3(在 Python 2 中会是 3)。这让字符串操作更直观。
8. 常见应用场景
- 用户输入清洗:用户提交表单时,用
strip()去掉首尾空格,用lower()统一邮箱地址大小写。 - 文件路径处理:用
split()提取文件名,用replace()转换路径分隔符。 - 日志分析:用
find()定位关键词位置,用切片提取特定段落的日志信息。 - 数据格式化:用
split()解析 CSV 行数据,用join()重新组合输出。 - 密码验证:用
isalnum()、isdigit()、isalpha()检查密码是否包含所需字符类型。 - 文本反转:
[::-1]快速实现字符串反转,用于判断回文或简单的编码。
❓ 常见问题
Q:单引号和双引号到底选哪个?为什么 Python 允许两种? A: 历史上 Python 的设计者认为给程序员选择权是好事。不同人有不同习惯:C/Java 程序员习惯双引号,JavaScript 程序员两种都用。建议统一用双引号,因为英文中常见单引号(it's、don't、can't),外部用双引号就不用转义了。但更重要的是一个项目里保持一致,不要混用。
Q:切片时的终点为什么取不到?比如
text[0:5]不包含索引 5? A: 这是 Python 的设计哲学——左闭右开([起点, 终点))。好处有两个:一是text[:5]好记(前 5 个字符),二是text[0:5]和text[5:10]正好无缝衔接,不会漏掉也不会重叠。你习惯了会发现这个设计很舒服。
Q:
find()和index()有什么区别? A: 它们功能一样,都是查找子串位置。区别是:find()找不到时返回-1,index()找不到时报错(ValueError)。日常用find()更安全。index()适合你确定"一定存在这个子串"的场景(比如从固定格式的数据中提取信息)。
Q:为什么字符串方法不直接修改原字符串?(比如
text.upper()后text并没有变)A: 因为字符串在 Python 中是不可变的(immutable)。一旦创建就不能修改。text.upper()实际上返回了一个新的字符串,原来的text保持不变。这和保护数据安全有关——如果你把一个字符串传递给某个函数,你可以确信它不会被偷偷改掉。如果你需要"修改"字符串,就用切片+拼接创建新字符串。
📖 小节
- 字符串有三种引号形式:单引号、双引号、三引号;推荐统一用双引号
- 转义字符
\n\t\\等用于表示特殊字符 - 原始字符串
r"..."中的反斜杠不转义,适合文件路径和正则表达式 - 索引从 0 开始,支持负数索引(
-1是最后一个字符) - 切片
[起点:终点:步长]可以取子串,终点不包含,步长为负可实现反转 - 常用方法:
strip()去空白、split()拆分、join()合并、find()查找、replace()替换 - 判断类方法:
isdigit()、isalpha()、isalnum()等用于输入验证 - 字符串是不可变的——所有"修改"操作都是创建新字符串
📝 作业
-
基础题(难度⭐):给定一个字符串
s = "Python programming is fun!",分别实现:- 提取前 6 个字符
- 提取最后 4 个字符
- 反转整个字符串
- 将所有字母转为大写
-
进阶题(难度⭐⭐):写一个"邮箱格式验证器"。给定一个邮箱地址
email = "user@example.com",检查它:- 是否包含
@符号 @符号前后是否都有内容(不为空)- 是否以
.com、.cn或.org结尾 - 输出每条检查的结果(True/False)提示:用
find()查找@位置,用切片提取前后部分。
- 是否包含
-
挑战题(难度⭐⭐⭐):写一个"脏数据清洗函数"。给定一个字符串:
TEXT 📖 仅展示data = " Alice, 25 , 北京 ; Bob , 30, 上海 ; Charlie , 22, 广州 "按
;拆分出每个人的数据,再按,拆分出每个字段,用strip()去掉每个字段的空白字符,最后以整齐的表格形式输出:TEXT 📖 仅展示姓名 年龄 城市 ───────────────── Alice 25 北京 Bob 30 上海 Charlie 22 广州