今天你 AI 赋能了吗?打开浏览器,在地址栏输入 xuefulu.ai ,按下 Enter 即可访问学府路1号!
2026年10月14日 星期三 10:40:08
常用网址: | | 学府路1号 https://xuefulu.ai | 下载 Python https://xuefulu.ai/Python.html | 下载 TRAE https://xuefulu.ai/Trae.html

一、字符串是什么

字符串就是一段文字。只要用引号包起来,不管是中文、英文、数字还是符号,都算字符串。

它是我们打交道最多的一种类型——网页上的内容、表格里的数据、用户输入的东西,拿到手里几乎都是字符串。

1.1 三种引号,随便挑

Python
a = "小满"          # 双引号
b = '小满'          # 单引号,和双引号完全一样
c = "他说:'你好'"   # 里面是单引号,外面就用双引号
d = '他说:"你好"'   # 里面是双引号,外面就用单引号

还有一种情况很常见:文字里面本来就有引号时,外用另一种引号就行,不用操心转义。

还有第三种:三引号,专门用来写跨好几行的文字。

Python
e = """第一行
第二行
第三行"""
print(e)
# 输出:
# 第一行
# 第二行
# 第三行
单引号和双引号没有区别,挑一个用着顺手的一直用就好。三引号的主要用途是写多行文字,或者在代码里写一段说明(第 5 篇《语法规范》里讲过的文档字符串)。

1.2 数一数有几个字:len()

Python
print(len("Python"))      # 6
print(len("你好世界"))     # 4     一个汉字算 1 个字符
print(len("  ab  "))      # 6     空格也算一个字符
len() 数的是字符个数,不是字节数。一个汉字算 1 个,所以“你好世界”是 4 而不是 8。这一点在检查输入长度时会用到。

1.3 问一句“里面有没有”:in

Python
s = "Python编程"
print("thon" in s)      # True    包含这一段
print("Java" in s)      # False   不包含
print("Py" not in s)    # False   反过来问“不包含”
print("p" in s)         # False   注意大小写敏感:小写 p 不在里面
in 是判断连着的几个字符有没有出现,不只是单个字。"thon" in "Python" 也是 True。要特别注意它是区分大小写的。

1.4 字符串改不了(很重要)

字符串属于不可变类型:创建出来之后,里面任何一个字符都不能单独修改。

Python
s = "hello"
s[0] = "H"
# 报错:TypeError: 'str' object does not support item assignment

想改只能重新拼一个新字符串,再让变量指向它:

Python
s = "hello"
s = "H" + s[1:]     # 取第 1 个到最后,前面接个 H
print(s)            # Hello
这一条会引出一个很实用的结论:字符串的方法都不会改动原字符串,而是返回一个新的。s.upper() 写完 s 本身没变,想用结果得接住——s2 = s.upper()。后面第六、七节的方法全都遵守这条。

二、引号与转义字符

有些字符没法直接打出来,比如“换行”“制表符”;还有些字符在字符串里有特殊身份,比如引号本身。这时候就要用反斜杠 \ 加一个字母来表示它,这叫转义字符。

写法名字作用实际效果
\n换行从这里换到下一行相当于按一次回车
\t制表符空出一段,用来对齐相当于按一次 Tab
\\反斜杠表示一个反斜杠本身显示为 \
\"双引号表示一个双引号本身显示为 "
\'单引号表示一个单引号本身显示为 '
Python
print("第一行\n第二行")      # \n 在这里换行
print("姓名\t年龄")          # \t 空一段,用来对齐
print("C:\\Users\\笔记")     # \\ 表示一个反斜杠
print("他说:\"你好\"")       # \" 表示引号本身

运行结果:

输出
第一行
第二行
姓名    年龄          ← 这里是一个 Tab(制表符),不是一串空格
C:\Users\笔记
他说:"你好"
前两行看着简单,但“看不见”的字符最容易惹麻烦。比如你想打印一个 Windows 路径 "C:\new\test",里面的 \n 会被当成“换行”、\t 会被当成“Tab”,结果路径被切得乱七八糟。
Python
print("C:\new\test")
# 实际输出(已经不是你想要的路径了):
# C:
# ew    est

这个问题有个更省事的解法:在引号前面加个 r,让反斜杠恢复成普通字符。这是第 11 节的内容,先记住有这么回事。

课程思政|工匠精神与严谨求实 · 看不见的字符最惹麻烦

反斜杠加一个字母,就变成了「换行」「制表」这些看不见的角色。打印一个 C:\new\test 路径,\n、\t 会悄悄把路径切得七零八落,程序还不报错。越是看不见的地方,越要盯紧;出了怪结果先怀疑这些隐身的字符,是程序员该有的警觉。

三、索引:取出一个字符

字符串是一串排好队的字符,每个字符都有一个位置编号。用 方括号 + 编号 就能把它单独取出来,这叫索引。

编号规则只有两条:从左往右从 0 开始,从右往左从 -1 开始。

字符Python
从左数(正索引)012345
从右数(负索引)-6-5-4-3-2-1

上表是 s = "Python" 的编号表。记不住从 0 开始,是新手最常犯的错。

Python
s = "Python"

print(s[0])      # P    第 0 个(也就是第一个)
print(s[1])      # y    第 1 个
print(s[5])      # n    最后 1 个(一共 6 个字符,编号到 5 为止)
print(s[-1])     # n    从右数第 1 个,也就是最后一个
print(s[-2])     # o    倒数第二个
s[-1] 是“取最后一个字符”的标准写法,非常好用——字符串多长都不用管。取第 1 个字符就写 s[0]、取最后一个就写 s[-1],别看元素总数。

3.1 越界会报错

编号超出范围就会报错:

Python
s = "Python"
print(s[6])
# 报错:IndexError: string index out of range
IndexError 的意思是“编号超出范围了”。"Python" 只有 6 个字符、编号是 0~5,写 s[6] 就多了一位。看到这个报错,先数一遍字符个数,再看看是不是把“从 1 开始”的直觉带进来了。

3.2 实战:从身份证号里取一位

身份证号是 18 位的字符串,每一位都有含义。想单独看某一位,索引最直接——比如第 17 位表示性别(奇数男、偶数女):

Python
id_no = '440583198704201234'

print('第 17 位(性别位):', id_no[16])
print('倒数第 2 位:', id_no[-2])
print('最后一位(校验码):', id_no[-1])

输出:

输出
第 17 位(性别位): 3
倒数第 2 位: 3
最后一位(校验码): 4

id_no[16] 和 id_no[-2] 取到的是同一个字符:「第 17 位」的下标是 16,差一位不报错、只会悄悄取错,这是这一段最常见的坑。想判性别还差一步,把字符转成整数再看奇偶:

Python
id_no = '440583198704201234'

print('男' if int(id_no[16]) % 2 else '女')

输出:

输出
男

还有个细节:最后一位可能是字母 X(代表校验值 10),所以它不能直接当数字用。完整的位序表、出生日期怎么切、X 怎么处理,都在《18-切片操作》第九节。

四、切片:取出一段

索引一次只能取一个字符。想取一串,就用切片。写法是在方括号里用冒号分开三个数字:

输出
字符串[起始位置 : 结束位置 : 步长]

最重要的一条规则:含头不含尾。起始位置要,结束位置不要。

4.1 先记住“含头不含尾”

Python
data = "0123456789"

print(data[2:5])    # 234     取编号 2、3、4,不含 5
print(data[0:3])    # 012     取编号 0、1、2,不含 3
print(data[-3:])    # 789     取最后三个
用一句话记:“写 2 到 5,取到 4 就停”。或者记成“右边那个数字是刹车,刹车的位置取不到”。这条规则字符串、列表、元组全都一样。

4.2 三种省略写法

写法含义例子结果
s[start:end]从 start 取到 end(不含 end)"0123456789"[2:5]234
s[:end]从头取到 end(不含 end)"0123456789"[:3]012
s[start:]从 start 一直取到最后"0123456789"[7:]789
s[:]整段照抄一份"0123456789"[:]0123456789
记法很直观:哪边没写数字,就是从哪边“到头”。前面不写=从头开始,后面不写=一直到尾。

4.3 步长:隔几个取一个

第三个数字是步长,默认是 1(一个一个取)。改成 2 就是每隔一个取一个:

Python
s = "0123456789"

print(s[::2])     # 02468   从头到尾,隔一个取一个
print(s[1::2])    # 13579   从 1 开始,隔一个取一个
print(s[1:8:2])   # 1357    从 1 取到 7,隔一个取一个
步长不写就是 1,所以 s[2:5] 和 s[2:5:1] 完全一样。日常用得最多的是 [::2](隔一个取)和下面的 [::-1](反转)。

4.4 反转:把整串倒过来

步长写成 -1,就是从后往前一个一个取,等于把字符串倒过来。这是 Python 里最简洁的反转写法:

Python
s = "Python"

print(s[::-1])    # nohtyP    整个倒过来
print(s[::-2])    # nhy       倒着取,隔一个取一个
判断一个词是不是回文(正着读反着读一样,比如 "上海自来水来自海上"),一行就够:
Python
word = "上海自来水来自海上"
print(word == word[::-1])     # True
这个 [::-1] 对列表也管用,第 8 篇里反转列表用的就是它。

4.5 实战:从身份证号里切出一段

还是那个 18 位的号码:出生年月日在第 7~14 位,后四位是第 15~18 位。两段都是切片一行的事:

Python
id_no = '440583198704201234'

print('出生年月日:', id_no[6:14])
print('后四位:', id_no[-4:])

输出:

输出
出生年月日: 19870420
后四位: 1234

[6:14] 按「含头不含尾」取到下标 6~13,正好 8 位;[-4:] 是从右数第 4 位一直取到末尾,不用先知道号码多长。取出来的 8 位还是字符串,所以能接着往下切:

Python
id_no = '440583198704201234'

birth = id_no[6:14]
print(f'{birth[0:4]}-{birth[4:6]}-{birth[6:8]}')

输出:

输出
1987-04-20

切片的结果可以接着切、接着拼——这正是「切片返回的还是同类型」带来的方便。位序表和性别判断的完整写法见《18-切片操作》第九节。

五、连接与重复

两个动作最常用:加号 + 把两段接起来,乘号 * 把一段重复几遍。

Python
print("珍珠" + "奶茶")                # 珍珠奶茶   接起来
print("Hello" + ", " + "World")   # Hello, World
print("-" * 10)                   # ----------  重复 10 遍
print("哈" * 3)                   # 哈哈哈
print("Ab" * 4)                   # AbAbAbAb

5.1 想拼数字,必须先转成字符串

Python
age = 18

print("我今年" + age + "岁")
# 报错:TypeError: can only concatenate str (not "int") to str

print("我今年" + str(age) + "岁")      # 我今年18岁   ✓ 先转换
print(f"我今年{age}岁")                # 我今年18岁   ✓ 更好的办法
str() 把别的东西变成字符串,这是最直接的解法。但如果要拼的内容比较多,用 f 字符串(第九节)会清爽得多,也不用一个个 str(),建议养成习惯。

5.2 一个容易误会的地方:print 里的逗号

有些人看到 print 里用逗号也能把几样东西连起来,就以为逗号是“字符串拼接”。不是的。逗号是 print 的分隔符,它只是在输出时把几样东西依次打印、中间自动加个空格:

写法本质是什么结果
print("我今年", 18, "岁")print 收到 3 个参数,依次打印、中间加空格我今年 18 岁
print("我今年" + str(18) + "岁")先用 + 拼成一个字符串,再交给 print我今年18岁
区别在结果上能看出来:逗号版本多了一个空格,加号版本没有。而且逗号版本不能存进变量——msg = "我今年", 18 得到的是元组不是字符串。想存下来、想精确控制格式,就用 + 或 f 字符串。

5.3 相邻的字符串会自动拼起来

还有一个语法小特性:两个字符串字面量挨着写,Python 会自动把它们拼成一个。

Python
msg = "Py" "thon"
print(msg)       # Python
这个特性知道就行,实际写代码不要故意这么用——容易看漏中间少了个逗号。"a" "b"(拼成 "ab")和 "a", "b"(元组)就差一个逗号,意思完全不同。

课程思政|诚信与职业操守 · 一段一段拼,才拼得完整

加号能把两段文字接起来,乘号能把一段重复几遍,拼的时候还得先把数字转成字符串。团队做一份报告也是这样,各写各的一段,格式和口径统一了才接得上。谁也别图省事省掉自己那一段,一个人的疏漏,整份材料都得返工。

六、常用方法之一:大小写与清理

方法是“跟着字符串后面用点叫出来”的功能,写法是 字符串.方法名(参数)。下面这些是日常用得最多的。

先看改大小写的四个:

方法作用例子结果
lower()全部变小写"Hello PY".lower()hello py
upper()全部变大写"hello py".upper()HELLO PY
capitalize()整个句子的首字母大写"hello python".capitalize()Hello python
title()每个单词的首字母都大写"hello python".title()Hello Python

再看清理两端空白的三个。名字里的 l 是 left(左),r 是 right(右):

方法清掉哪儿例子(原串带前后空格)结果
strip()两端都清" hi ".strip()"hi"
lstrip()只清左边" hi ".lstrip()"hi "
rstrip()只清右边" hi ".rstrip()" hi"
Python
s = "  Hello World  "

print(s.lower())        # "  hello world  "
print(s.upper())        # "  HELLO WORLD  "
print(s.strip())        # "Hello World"        两端空格没了
print(s.lstrip())       # "Hello World  "      只清左边
print(s.rstrip())       # "  Hello World"      只清右边
print(s.title())        # "  Hello World  "    每个单词首字母大写
⚠️ 再强调一次:这些方法都不会改动原来的 s,只是返回一个新字符串。s.strip() 写完 s 还是带空格的,必须写 s = s.strip() 才会真的生效——这是新手最容易漏的一步。
strip() 在处理用户输入时是必备的。用户在 input() 里很容易多打一个空格,不清理就会影响后面的比较和转换:
Python
name = input("请输入姓名:").strip()      # 顺手清掉两端的空格
注意只能这样连着写,不能先 input().strip() 再指望原变量变了。

七、常用方法之二:查找、替换、分割、合并

7.1 找位置:find() 和 count()

Python
t = "珍珠,椰果,珍珠,布丁"

print(t.find("椰果"))     # 3     返回它从第几个字符开始
print(t.find("西瓜"))     # -1    找不到返回 -1(不会报错)
print(t.count("珍珠"))    # 2     出现过几次
方法作用找不到时
find(x)返回 x 第一次出现的位置编号返回 -1,不报错
index(x)同上报 ValueError 让程序中断
count(x)数一数 x 出现了几次返回 0
x in s判断有没有 x返回 False
不确定找的东西一定在,用 find() 更安全——找不到给你个 -1,程序还能往下走。index() 找不到直接崩,除非你确定它一定存在,否则别用。

7.2 换内容:replace()

Python
t = "珍珠,椰果,珍珠,布丁"
print(t.replace("珍珠", "西米"))     # 西米,椰果,西米,布丁
print(t.replace("珍珠", "西米", 1))  # 西米,椰果,珍珠,布丁   只换第 1 处
replace() 默认全换;加上第三个参数可以限制只换前几处。它同样是返回新字符串,原串不动。

7.3 分割:split()

把一个字符串按某个符号切开,变成列表。这是处理表格数据的第一步。

Python
line = "奶茶,大杯,三分糖"
print(line.split(","))      # ['奶茶', '大杯', '三分糖']

data = "2026-09-20"
print(data.split("-"))      # ['2026', '09', '20']
写法含义结果
"a,b,c".split(",")按逗号切['a', 'b', 'c']
"a b c".split()不写参数:按空白切,并自动去掉连续空格['a', 'b', 'c']
" a b ".split()不写参数时,两端空白自动丢掉['a', 'b']
"a,b,,c".split(",")中间是空的,也会留下一项空字符串['a', 'b', '', 'c']
"a-b-c".split("-", 1)限制只切 1 次['a', 'b-c']
不写参数和写参数差别很大。split() 按任意空白切、还顺手把多余空格吃掉,处理用户输入最省事;split(",") 是严格按逗号切,逗号之间是空的就是空字符串。看见结果里出现空字符串 '',通常是数据里多打了分隔符。

7.4 合起来:join()

join() 是 split() 的反动作:把一个列表用某个分隔符合成一个字符串。

Python
words = ["珍珠", "椰果", "布丁"]
print(" ".join(words))      # 珍珠 椰果 布丁     用空格连

nums = ["2026", "09", "20"]
print("-".join(nums))       # 2026-09-20        用横线连

print("".join(["奶", "茶"]))  # 奶茶              不用分隔符就直接贴
⚠️ join() 的写法容易记反:分隔符在前、列表在后。是 "-".join(列表),不是 列表.join("-")。另外,列表里的元素必须全是字符串,装的是数字会报错,要先用 str() 转一遍。
Python
print("-".join([1, 2, 3]))
# 报错:TypeError: sequence item 0: expected str instance, int found

print("-".join(str(n) for n in [1, 2, 3]))     # 1-2-3   ✓ 先转成字符串
split() 和 join() 是一对,合起来能干很多活。比如把 "2026-09-20" 换成斜杠格式:
Python
d = "2026-09-20"
print("/".join(d.split("-")))     # 2026/09/20
先切开、再用新符号拼回去。

八、常用方法之三:判断类

这一类方法的共同点是:返回值是 True 或 False,专门用来检查字符串“符不符合某种样子”。常配合 if 使用。

方法它问的是是 True 的例子是 False 的例子
isdigit()是不是全是数字"12345""abc123"、"12.5"
isalpha()是不是全是字母"abc""abc123"、"ab c"
isalnum()是不是字母或数字(都行)"abc123""ab c"、"a-b"
isspace()是不是全是空白" ""a "
startswith(x)是不是以 x 开头"hello".startswith("he")"hello".startswith("lo")
endswith(x)是不是以 x 结尾"hello".endswith("lo")"hello".endswith("he")
Python
print("12345".isdigit())            # True    全是数字
print("abc123".isdigit())           # False   有字母
print("12.5".isdigit())             # False   有小数点!
print("abc123".isalpha())           # False   有数字
print("abc123".isalnum())           # True    字母数字都有,算通过
print("hello".startswith("he"))     # True
print("hello".endswith("lo"))       # True
⚠️ "12.5".isdigit() 是 False,这是最坑的一条。因为它带小数点,而小数点不是“数字字符”。同样,带负号的 "-5".isdigit() 也是 False。所以别用 isdigit() 去验证“是不是合法的小数”——那种情况应该直接 try 一下能不能转成 float。
判断用户输入是不是整数,isdigit() 很好用:
Python
age_text = input("请输入年龄:").strip()
if age_text.isdigit():
    age = int(age_text)
    print(f"明年你 {age + 1} 岁")
else:
    print("请输入纯数字,不要带小数点和符号")
这段先判断再转换,就不会因为用户乱输而让程序崩掉。

AI 助手小贴士|字符串方法十几个,让 AI 收成一张速查表再挑出易错的。

打开任意 AI 对话工具(网页版或 App 都可以),试试这样问:把 str 最常用的 12 个方法整理成表:方法名、作用、一行示例;再挑 3 个最容易拼错的方法提醒我

九、格式化:f 字符串(重点)

把变量塞进一句话里,最方便的办法就是在引号前面加一个 f,然后在句子里用花括号 {} 把它圈起来。这就是 f 字符串(f 是 format 的缩写)。

Python
name = "小满"
age = 18

print(f"我的名字是{name},今年{age}岁")
# 我的名字是小满,今年18岁
对比一下老写法就知道它好在哪——左边是 f 字符串,右边要写一堆引号和加号,还容易漏掉 str():
Python
f"我今年{age}岁"                    # 清爽
"我今年" + str(age) + "岁"          # 繁琐
f 必须紧贴在引号前面,中间不能有空格,写成 f "..." 是错的。

9.1 花括号里能放什么

只要是一段能算出结果的表达式,都可以放进去:

放什么写法结果
变量f"你好{name}"你好小满
算式f"明年{age + 1}岁"明年19岁
函数调用f"名字长度{len(name)}"名字长度2
方法调用f"大写{name.upper()}"大写小满
Python
score = 92.56789

print(f"明年我就{age + 1}岁了")        # 花括号里直接算
print(f"名字有{len(name)}个字")       # 花括号里调用函数

9.2 控制显示的格式(很有用)

在变量后面加个冒号,再写格式要求,就能控制小数位、对齐、千分位这些。写法是 {变量:格式}:

格式作用例子结果
.2f保留 2 位小数f"{92.56789:.2f}"92.57
.1f保留 1 位小数f"{92.56789:.1f}"92.6
.0f不要小数f"{92.56789:.0f}"93
.1%变成百分比f"{0.856:.1%}"85.6%
,加千分位逗号f"{1234567:,}"1,234,567
05d补零到 5 位(整数)f"{50:05d}"00050
>6右对齐,宽度 6f"[{name:>6}]"[    小满]
<6左对齐,宽度 6f"[{name:<6}]"[小满    ]
^6居中,宽度 6f"[{name:^6}]"[  小满  ]
Python
score = 92.56789
price = 50
total = 1234567

print(f"得分:{score:.2f}")        # 得分:92.57     保留 2 位小数
print(f"得分:{score:.1f}")        # 得分:92.6
print(f"正确率:{0.856:.1%}")      # 正确率:85.6%   变成百分比
print(f"总额:{total:,}")          # 总额:1,234,567 加千分位
print(f"编号:{price:05d}")        # 编号:00050     补零到 5 位
算 BMI、平均分、折扣率这类场景,.2f 几乎是必写的——不然会打印出 21.77777777777778 这种一长串。写 :.2f 就干净了。

9.3 想输出花括号本身

因为 {} 有特殊用途,想真的打印出花括号,要写两个:

Python
print(f"{{}}")              # {}        两个花括号变成一个字面花括号
print(f"{{{age}}}")         # {18}      外面两个当字面、里面那个还是变量

课程思政|科技自立自强 · 新工具要学,老代码要读

f 字符串让变量直接嵌进句子里,比一堆引号和加号清爽太多,这是新版本 Python 给我们的好工具。好工具要主动学,旧写法也得看得懂——技术一直在往前走,愿意换新工具、也肯回头读老代码的人,才不会被时代落下。

十、老写法:.format() 与 %

f 字符串是较新的 Python 3 版本 才有的。在那之前,大家用另外两种写法。你自己写代码请优先用 f 字符串,但看别人的代码、或者遇到老教材时会碰到这两种,认识就行。

下面同一个例子的三种写法对照:

写法代码说明
f 字符串(推荐)f"我是{name},今年{age}岁"{} 里直接写变量,最直观
.format()"我是{},今年{}岁".format(name, age)用 {} 占位,参数按顺序填
%"我是%s,今年%d岁" % (name, age)老式写法,类似 C 语言
Python
name = "小满"
age = 19
score = 92.56789

# 写法一:f 字符串(推荐)
print(f"我是{name},今年{age}岁,得分{score:.2f}")

# 写法二:.format()
print("我是{},今年{}岁。".format(name, age))
print("我是{nm},今年{ag}岁。".format(ag=age, nm=name))    # 也能起名字,顺序可换
print("得分:{:.2f}".format(score))

# 写法三:% 占位符
print("我是%s,今年%d岁。" % (name, age))
print("得分:%.2f" % score)
% 占位符对应的类型
%s字符串(也能塞别的,会自动转成字符串)
%d整数
%.2f浮点数,保留 2 位小数
记一条就够了:新代码一律用 f 字符串。它可读性最好、写起来最短、运行也最快。.format() 和 % 只需要能看懂——看到 %s 知道那是“这里要填个字符串”,看到 {0} 知道那是“填第一个参数”。

十一、r:原始字符串

回到第二节留下的问题:写文件路径时,路径里的 \n、\t 会被当成转义符,把路径搞得面目全非。

Python
print("C:\new_folder\temp")
# 你以为会打印路径,实际打印出:
# C:
# ew_folder	temp

解决的第一个办法是把每个反斜杠都写成两个(\\),但这又长又容易漏。

更省事的办法是在引号前面加一个 r。加了 r 之后,字符串里的反斜杠就变回普通字符,什么转义都不认了——这就是原始字符串(r 是 raw 的缩写)。

写法代码打印出来
不加 r"C:\new\temp"被吃掉了,变成换行和 Tab
加 rr"C:\new\temp"C:\new\temp ✓ 原样显示
手动双反斜杠"C:\\new\\temp"C:\new\temp ✓ 但要写一倍的多,容易漏
Python
# 加了 r,\n 和 \t 就是普通的两个字符
print(r"C:\new_folder\temp")       # C:\new_folder\temp

# 写文件路径:直接原样抄路径就行,不用一个个加反斜杠
path = r"C:\Users\小满\Desktop\笔记.txt"
print(path)                        # C:\Users\小满\Desktop\笔记.txt
凡是 Windows 路径,养成习惯加 r。直接从“地址栏”或者“复制文件路径”里粘过来,前面补个 r 就完事,不用管里面有几个 \、也不用担心哪个字母组合会被当转义符。

11.1 r 也有管不到的地方

有一条限制:原始字符串不能以单个反斜杠结尾,因为那个反斜杠会把结尾的引号“挡住”,Python 就不知道字符串在哪结束了。

Python
p = r"C:\Users\"      # 报错 SyntaxError: unterminated string literal
# 解决办法:单独拼一个反斜杠,或者干脆不加 r 用双反斜杠
p = r"C:\Users" + "\\"
这种情况很少遇到,记住“r 字符串的结尾别是单个反斜杠”就行,真碰到就把它拆成两段拼起来。

11.2 r 还常用在哪儿

另一个高频场景是正则表达式——里面全是反斜杠,不加 r 会疯掉。不过正则属于进阶内容,这里知道“r 是为大量反斜杠准备的”就够了。

Python
import re
# 正则里 \d 表示数字,不加 r 就要写成 \\d
print(re.findall(r"\d+", "订单号 20260920"))
# ['20260920']

十二、f 和 r 一起用(fr)

两个前缀解决的问题不一样:f 管“能不能嵌变量”,r 管“反斜杠要不要转义”。它们可以叠着写,写成 fr"..." 或 rf"...",两种顺序都行。

前缀解决的问题路径里的反斜杠{} 能嵌变量吗
不加——会被当转义符,出问题不能
f能嵌入变量和表达式仍然会被转义能
r反斜杠不转义原样保留不能
fr / rf两个都要原样保留能

看实际效果——变量是文件夹名,路径又带反斜杠,正好需要两个一起:

Python
folder = "文档"

print(f"C:\temp\{folder}.csv")
# ✗ 出事:\t 是「跳到下一个制表位」,路径里凭空多了一个 Tab

print(r"C:\temp\{folder}.csv")
# ✗ 也不行:原样输出,{folder} 不会被替换成"文档"

print(fr"C:\temp\{folder}.csv")
# ✓ 正确:C:\temp\文档.csv
Python
folder = "文档"

path1 = fr"C:\Users\小满\Desktop\{folder}\报告.csv"
path2 = rf"C:\Users\小满\Desktop\{folder}\报告.csv"

print(path1)     # C:\Users\小满\Desktop\文档\报告.csv
print(path2)     # C:\Users\小满\Desktop\文档\报告.csv
顺序随便,效果完全一样。fr 和 rf 都是“既要嵌入变量、又要反斜杠不转义”,不用纠结哪个对。前面说的不能以单个反斜杠结尾的限制,fr 一样适用。大写 FR、Rf 也照样能跑,但习惯上小写更常见。

12.1 一个容易忘的细节

用了 fr 之后,{} 仍然会被当成变量占位符。如果路径里真的有个花括号(很少见),还是要写成两个:

Python
folder = "文档"
print(fr"C:\data\{{临时}}\{folder}.txt")     # C:\data\{临时}\文档.txt

十三、综合例子

把前面学的串起来,做两个贴近实际的练习。

13.1 处理一行表格数据

假设从文件里读进来一行学生数据,格式是 学号,姓名,成绩,但里面有些地方多打了空格,需要整理出来:

Python
line = "  2026001, 小满 ,85.5  "

# 第一步:先清掉两端多余的空白
line = line.strip()
print(f"清理后:{line!r}")        # '2026001, 小满 ,85.5'

# 第二步:按逗号切开
parts = line.split(",")
print(f"切开后:{parts}")         # ['2026001', ' 小满 ', '85.5']

# 第三步:把每一项两端空格清掉
sid = parts[0].strip()
name = parts[1].strip()
score = float(parts[2].strip())   # 成绩要能算,转成小数

# 第四步:格式化输出
print(f"学号:{sid}")
print(f"姓名:{name}")
print(f"成绩:{score:.1f}")
print(f"是否及格:{score >= 60}")

运行结果:

Python
清理后:'2026001, 小满 ,85.5'
切开后:['2026001', ' 小满 ', '85.5']
学号:2026001
姓名:小满
成绩:85.5
是否及格:True
这四步是处理文本数据的固定套路:strip() → split() → 逐项 strip() → 该转的转。注意第三步里每一项都单独 strip() 了一遍,因为外层的 strip() 管不到逗号里面的空格。

13.2 生成带变量的文件路径

Python
name = "小满"
year = 2026
month = 9

filename = fr"D:\报表\{year}年\{month}月\{name}的工资表.csv"
print(filename)
# D:\报表\2026年\9月\小满的工资表.csv

# 想补零成 09 月,用格式规格
filename2 = fr"D:\报表\{year}年\{month:02d}月\{name}的工资表.csv"
print(filename2)
# D:\报表\2026年\09月\小满的工资表.csv
{month:02d} 的意思是“按整数补零到 2 位”,9 就变成 09。生成文件名、编号、日期的时候很常用。

13.3 统计一句话里的信息

Python
sentence = "Python 是一种很好用的编程语言"

print(f"总长度:{len(sentence)}")
print(f"有无空格:{sentence.count(' ')} 个")
print(f"是否以 Python 开头:{sentence.startswith('Python')}")

# 按空格切开,看看有几个词
words = sentence.split(" ")
print(f"词数:{len(words)}")
print(f"第一个词:{words[0]}")

# 倒过来看
print(f"倒过来:{sentence[::-1]}")
print(f"前 6 个字:{sentence[:6]}")

AI 助手小贴士|字符串处理是练手感的好题材,让 AI 出题并逐行点评。

打开任意 AI 对话工具(网页版或 App 都可以),试试这样问:出 3 道字符串处理小题:统计元音字母个数、把手机号中间四位换成星号、判断回文。我写完你逐行点评

课程思政|数据安全与法治素养 · 清洗别人数据,更要守规矩

这一节的例子是把一行 学号,姓名,成绩 里的多余空格清理干净,看着只是做整理,手里握的却是别人的信息。数据能随手处理,不等于能随手传播;练手时用假数据、把真实的姓名和联系方式脱敏,是数据从业者的底线。

十四、常见问题

下面这些报错和坑,初学阶段几乎每个人都会碰一遍。看到眼熟的那条,照着“怎么办”改就行。

现象 / 报错原因怎么办
TypeError: can only concatenate str (not "int") to str字符串和数字直接用 + 拼先 str(n) 转换,或用 f 字符串 f"年龄{age}"
IndexError: string index out of range索引超出范围(比如 6 个字符却取 s[6])编号是 0 ~ len(s)-1;取最后一个用 s[-1]
TypeError: 'str' object does not support item assignment想改字符串里的某个字符字符串不可变。重新拼一个:s = "H" + s[1:]
len(5) 报 TypeError: object of type 'int' has no len()len() 只能量字符串、列表这些,不能量数字先转成字符串:len(str(5))
s.upper() 写完 s 却没变方法返回新串,不会改原串接住返回值:s = s.upper()(strip() 同理)
int("3.5") 报 ValueErrorint() 不认小数点两步走:int(float("3.5"));判断时也别用 isdigit()
"12.5".isdigit() 是 False小数点不是“数字字符”别用 isdigit() 验证小数,直接 try 转 float
"abc".index("z") 报 ValueError: substring not foundindex() 找不到会报错不确定就用 find(),找不到返回 -1
切片取多或取少了一位忘了“含头不含尾”s[0:5] 取到的是第 0~4 个,共 5 个字符
切片结果和预想差一个字符,多出空格编号没数准(空格也占一位)把字符串和编号一起打出来核对:for i, ch in enumerate(s): print(i, repr(ch))
"-".join([1, 2, 3]) 报 TypeError列表里是数字,join 只接受字符串先转:"-".join(str(n) for n in [1, 2, 3])
split() 结果里出现空字符串 ''数据里多打了分隔符(如 "a,,b")清掉空项:parts = [p for p in parts if p]
路径里的 \t、\n 被吃掉了反斜杠被当成转义符引号前加 r:写成 r"C:\new\test"
f"C:\data\{name}.txt" 路径不对只加了 f,反斜杠仍在转义两个一起加:写成 fr"C:\data\{name}.txt"
f"{{}}" 想输出花括号却报错/没输出花括号是占位符,有特殊含义字面花括号要写两个:f"{{}}"
遇到报错先做两件事:① 看最后一行,那里才是真正的原因;② 看到 TypeError 就去查 type()(是不是字符串和数字混着用了),看到 IndexError 就去数编号,看到 ValueError 就去查要转换的内容合不合法。

AI 助手小贴士|让 AI 给代码逐行加注释是它最擅长的活之一——连注释风格都能指定,这是「用 AI 学注释」最直接的练法。

打开任意 AI 对话工具(网页版或 App 都可以),试试这样问:给下面这段字符串处理代码的每一行加上简洁的中文行注释,说明这行在做什么,不要复述代码本身:<粘贴代码>

十五、随堂自测(12 题)

点击选项即可判分,答错的题会立刻显示解析。做完全部题目会给出正确率和错题清单。

已答 0 / 12 · 正确 0 —

1关于字符串,下面哪句话是对的?

  • A. 可以用 s[0] = "H" 把第一个字符改掉
  • B. 字符串里的字符可以随意增删
  • C. 字符串一旦创建就不能修改,想改只能重新生成一个新字符串
  • D. 只有用单引号定义的字符串才不可变
答案:C。字符串是不可变类型,s[0] = "H" 会报 TypeError。而且 s.upper()、s.replace() 这些方法都不会改动原字符串,只是返回一个新的给你。

2len("你好世界") 的结果是多少?

  • A. 4
  • B. 8
  • C. 2
  • D. 报错
答案:A。len() 数的是字符个数,不是字节数。一个汉字算 1 个字符,所以“你好世界”是 4。空格也占一位,len(" ab ") 是 6。

3s = "Python",s[::-1] 的结果是什么?

  • A. "Python"
  • B. "Pto"
  • C. "yhn"
  • D. "nohtyP"
答案:D。步长写 -1 表示从后往前一个一个取,就是把整串反过来。s[::2] 是隔一个取一个得 "Pto",s[1::2] 得 "yhn"。

4" hello ".strip() 的结果是什么?

  • A. " hello "(没变化)
  • B. "hello"(两端空格都去掉)
  • C. "hello "(只去左边)
  • D. " hello"(只去右边)
答案:B。strip() 去掉两端的空白。只去左边用 lstrip()、只去右边用 rstrip()。处理用户输入时最常用它清掉多打的空格。

5"苹果,香蕉,苹果".split(",") 的结果是什么?

  • A. "苹果香蕉苹果"
  • B. "苹果 香蕉 苹果"
  • C. ['苹果', '香蕉', '苹果']
  • D. ('苹果', '香蕉', '苹果')
答案:C。split() 按你给的分隔符切开,返回的是列表(方括号),既不是字符串也不是元组。这是读 CSV 表格数据的第一步。

6有一批日期 ["2026", "09", "20"],想拼成 "2026-09-20",怎么写?

  • A. "-".join(["2026", "09", "20"])
  • B. ["2026", "09", "20"].join("-")
  • C. "-".split(["2026", "09", "20"])
  • D. "-" + ["2026", "09", "20"]
答案:A。join() 是用分隔符去连接一个列表,写法是 分隔符.join(列表)——分隔符在前、列表在后。B 把顺序写反了,C 用错了方法(split 是切的),D 字符串不能直接和列表相加。

7f"{3.14159:.2f}" 的结果是什么?

  • A. "3.14159"
  • B. "3.1"
  • C. "3.142"
  • D. "3.14"
答案:D。:.2f 表示保留 2 位小数,结果是 3.14。:.1f 是 1 位、:.0f 是不留小数。算平均分、BMI、折扣率时几乎都要写上它。

8想判断用户输入的一串字符是不是全是数字,用哪个方法?

  • A. "12345".isalpha()
  • B. "12345".isdigit()
  • C. "12345".isalnum()
  • D. "12345".startswith("1")
答案:B。isdigit() 判断是不是全是数字。isalpha() 是判断全是字母,isalnum() 是字母或数字都算通过(所以 "abc123".isalnum() 也是 True),startswith() 只看开头第一个字符。

9Windows 路径 "C:\new\test" 里的 \n、\t 老被当成转义符,在引号前加什么能解决?

  • A. f
  • B. b
  • C. r
  • D. u
答案:C。r 是 raw(原始)的缩写,加了它字符串里的反斜杠就是普通字符,\n 不会再变成换行。f 是管嵌入变量的,解决不了转义问题。

10变量 name = "统计",想拼出路径 C:\data\统计.csv,下面哪种写法最好?

  • A. fr"C:\data\{name}.csv"
  • B. f"C:\data\{name}.csv"
  • C. r"C:\data\{name}.csv"
  • D. f"C:\\data\\{name}.csv"
答案:A。fr 把两个前缀的好处合起来:f 让 {} 能嵌入变量,r 让反斜杠不被转义。B 只加 f,路径里若出现 \t、\n 这类真转义(比如 \temp)就会出问题;C 只加 r,{} 不会被替换成变量值;D 要手写双反斜杠,容易漏。

11身份证号 id_no = '440583198704201234',id_no[-2] 取到的是哪个字符?

  • A. '4'(最后一位校验码)
  • B. '3'(倒数第二位,也就是性别位)
  • C. '2'(倒数第四位)
  • D. 报 IndexError
答案:B。负索引从 -1 开始数:-1 是最后一位 '4',-2 就是倒数第二位 '3',也正是第 17 位的性别位(奇数男、偶数女)。18 位号码用 -1、-2 这样的下标一定不会越界。

1218 位的身份证号,写 id_no[-4:] 取到的是哪几位?

  • A. 前四位
  • B. 出生年份
  • C. 整个号码
  • D. 后四位
答案:D。[-4:] 表示「从右数第 4 位开始,一直取到末尾」,也就是后四位(第 15~18 位)。等价的正索引写法是 [14:]——负索引的好处是不用先数总长度。