Day07 · 字符串(一)
阶段:阶段一 · 核心基础 | 前置:Day06 | 技术基准:Python 3.15.0
学习目标
- 掌握字符串的三种定义方式:单引号、双引号、三引号
- 理解字符串的不可变性,知道"修改字符串"其实是生成新串
- 熟记常用转义字符,会用原始字符串
r''描述路径与正则 - 掌握索引(正负)与切片
s[start:end:step],能做负步长逆序 - 会用
len()取长度,知道字符串与+、*运算的规则
一、什么是字符串
字符串(str)就是一串字符,是 Python 里最常用的文本数据类型。它属于序列类型(Sequence)------按顺序排成一列,可以逐个取出来。
二、定义字符串:三种引号
2.1、单引号与双引号
Python 里单引号 '...' 和双引号 "..." 完全等价,任选其一。选哪种的实用规则是:字符串内部需要出现哪种引号,就用另一种包外面。
python
# Author: XiaoJia
s1 = 'Hello Python' # 单引号
s2 = "Hello Python" # 双引号,效果相同
s3 = '他说:"你好"' # 内部有双引号,外面用单引号
s4 = "it's a book" # 内部有单引号,外面用双引号
print(s1, s2, s3, s4, sep="\n")
输出:
text
Hello Python
Hello Python
他说:"你好"
it's a book
2.2、三引号:多行字符串
三个引号 """...""" 或 '''...''' 可以跨行,保留换行和缩进,非常适合写大段文本、SQL、HTML、文档注释。
python
poem = """床前明月光,
疑是地上霜。
举头望明月,
低头思故乡。"""
print(poem)
html = """<html>
<body>Hello Python</body>
</html>"""
print(html)
提示:Day04 讲过,函数/类开头的三引号字符串就是文档字符串(Docstring),本质也是普通字符串。
三、字符串是不可变的
字符串一旦创建,就不能原地修改。所谓"改字符串",其实是造一个新字符串。
python
s = "hello"
# s[0] = "H" # TypeError: 'str' object does not support item assignment
# 正确做法:造一个新字符串
s2 = "H" + s[1:]
print(s) # hello 原串没变
print(s2) # Hello 新串
记住:所有字符串方法都返回新字符串,不改动原串。
四、转义字符
有些字符有特殊含义(比如引号、换行),想表示它们本身就要用反斜杠 \ 转义。
| 转义符 | 含义 |
|---|---|
\n |
换行 |
\t |
横向制表符(Tab) |
\\ |
一个反斜杠 |
\' |
单引号 |
\" |
双引号 |
\r |
回车(光标回到行首) |
\b |
退格(删除前一个字符) |
\uXXXX |
Unicode 字符(按码点) |
python
print("他说:\"你好\"") # 他说:"你好"
print('it\'s a book') # it's a book
print("第一行\n第二行") # \n 换行
print("姓名\t年龄") # 姓名 年龄
print("C:\\Users\\XiaoJia") # C:\Users\XiaoJia
4.1、转义字符到底解决什么问题
有些字符你想"原样打出来",但它们在 Python 里另有含义。比如字符串用双引号包着,里面再来一个双引号,解释器会误以为"字符串到这里结束了"。这时候就得用反斜杠 \ 告诉解释器:"后面这个字符只是普通字符,别当成语法符号"。
python
# 不加转义会怎样?下面这行会报 SyntaxError
# print("他说:"你好"") # 第二个 " 被当成字符串结尾
# 加了转义就正常
print("他说:\"你好\"") # 他说:"你好"
\n、\t 这类则相反------它们是"看不见的控制字符",反斜杠让普通字母 n 变成"换行"这个动作。常见的还有 \u 加四个十六进制数,表示一个 Unicode 字符:
python
print("\u4f60\u597d") # 你好 按 Unicode 码点输出
print("\u2605") # ★ 一颗星
五、原始字符串 r''
写 Windows 路径或正则表达式时,每个反斜杠都要写成 \\,很麻烦。在引号前加 r(raw),反斜杠就"所见即所得",不再转义。
python
path1 = "C:\\Users\\XiaoJia\\python" # 普通写法,每个 \ 都要转义
path2 = r"C:\Users\XiaoJia\python" # 原始字符串,直接写路径
print(path1) # C:\Users\XiaoJia\python
print(path2) # C:\Users\XiaoJia\python
print(path1 == path2) # True
# 正则场景也常用 r
import re
print(re.findall(r"\d+", "编号123abc456")) # ['123', '456']
注意:原始字符串里最后一个字符不能是单个反斜杠 (
r"\"会报错),因为反斜杠还在转义引号。路径末尾要反斜杠时写成r"C:\path\\"或path + "\\"。
六、索引:按下标取字符
字符串最左端是第 0 个,向右依次 +1;也可以用负数从右往左数,最右是 -1。
python
# Author: XiaoJia
s = "Hello Python"
# 索引:0123456789...(H=0, e=1, ..., P=6, ...)
print(s[0]) # H
print(s[6]) # P
print(s[-1]) # n 最后一个字符
print(s[-7]) # 空格(第 6 位)
长度为 L 的字符串,最后一个字符下标是 L-1;越界会报 IndexError。
python
# print(s[100]) # IndexError: string index out of range
七、切片:截取一段
切片语法 s[start:end:step],从 start 取到 end 之前(不含 end),可带步长。三个参数都能省略。
python
s = "Hello Python"
print(s[0:5]) # Hello [0,5)
print(s[:5]) # Hello 省略 start = 从 0 开始
print(s[6:]) # Python 省略 end = 到最后
print(s[-6:]) # Python 负数从右数
print(s[::2]) # HloPto 步长 2,隔一个取
print(s[::-1]) # nohtyP olleH 步长 -1,字符串反转!
print(s[0:100]) # Hello Python 切片越界不报错,自动截到末尾
切片口诀:左含右不含,省略即到头;步长为负,从右往左走。
python
# 实用小例:去首尾、取奇偶位
word = "abcdefg"
print(word[1:-1]) # bcdef 去掉首尾
print(word[::2]) # aceg 偶数位(0,2,4,6)
print(word[1::2]) # bdf 奇数位(1,3,5)
5.1、索引与切片的常见坑
新手在索引切片上常犯三个错,小嘉一次讲清:
- 下标从 0 而不是 1 开始 :第一个字符是
s[0],不是s[1]。 - 切片右边界取不到 :
s[0:5]取的是下标0、1、2、3、4,不包含5,所以长度正好等于5 - 0 = 5。 - 负索引从 -1 开始 :最后一个字符是
s[-1],不是s[-0](-0等于0)。
python
# Author: XiaoJia
word = "Python"
# 下标: P y t h o n
# 正数: 0 1 2 3 4 5
# 负数:-6 -5 -4 -3 -2 -1
print(word[0]) # P 第一个
print(word[5]) # n 最后一个
print(word[-1]) # n 最后一个(等价写法)
print(word[0:6]) # Python 左含右不含,长度 6
print(word[:3]) # Pyt 省略 start
print(word[3:]) # hon 省略 end
还有一个反直觉但好用的点:切片越界不报错,索引越界才报错。
python
s = "abc"
print(s[1:100]) # bc 切片自动截到末尾,不报错
# print(s[100]) # 索引越界 → IndexError
八、len()、+ 与 *
8.1、len() 取长度
python
print(len("Hello")) # 5
print(len("")) # 0
print(len("你好")) # 2 中文一个字算 1 个字符
8.2、字符串拼接 + 与重复 *
python
s1 = "Hello"
s2 = "World"
print(s1 + " " + s2) # Hello World
print("=" * 30) # ==============================
print("Ha" * 3) # HaHaHa
规则:
+只能两个字符串相加;字符串和数字相加要先str()转换。*的另一个操作数必须是整数,表示重复次数。- 运算结果都是新字符串,原串不变。
python
# 常见错误:字符串和数字直接相加
# print("年龄:" + 18) # TypeError
print("年龄:" + str(18)) # 年龄:18
python
# 常见错误:字符串和数字直接相加
# print("年龄:" + 18) # TypeError
print("年龄:" + str(18)) # 年龄:18
# 乘 0 或负整数会得到空串
print("Ha" * 0) # 空串
print("ab" * -3) # 空串
+ 和 * 都不会改动原字符串,而是返回一个全新字符串。这跟 Day06 讲的"字符串不可变"是一回事------你看到的所有字符串运算,本质都是"读老串、造新串"。
8.3、字符串与数字相加为什么会报错
新手常写 print("第" + 1 + "名"),结果报 TypeError: can only concatenate str (not "int") to str。原因很简单:+ 在字符串里表示"拼接",它要求两边都是字符串;而 1 是整数,类型对不上,Python 不会自作主张帮你转换(这正是 Day01 讲的"强类型")。解决办法就是先用 str() 把数字转成字符串,或者干脆用 f-string:
python
# 错误:str + int
# print("第" + 1 + "名") # TypeError
# 对:先转字符串
print("第" + str(1) + "名") # 第1名
# 更推荐:f-string,自动处理类型
print(f"第{1}名") # 第1名
这个小坑本质上还是"字符串不可变、+ 只认字符串"这条规则的延伸。理解了类型边界,报错信息就不再可怕。
九、综合小例:手搓"首字母大写"
Day07 学的知识可以组合起来解决一个小问题:把 "hello python" 变成 "Hello Python",不调用现成的 title(),自己用切片和拼接实现。
python
# Author: XiaoJia
s = "hello python"
# 第一步:把第一个单词首字母大写
result = s[0].upper() + s[1:6] # "Hello "
# 第二步:找到第二个单词,把它的首字母大写
space_pos = s.find(" ") # 6
result = result + s[space_pos + 1].upper() + s[space_pos + 2:]
print(result) # Hello Python
这个例子把"切片取一段、upper() 改大小写、+ 拼接、find() 定位空格"四个知识点串了起来。等 Day08 学了 split()、join(),这种需求会写得更简洁------但思路是一样的:切片取出要改的片段,改完再拼回去。
小嘉提醒:因为字符串不可变,你永远是"造新串",而不是"改老串"。理解这一点,后面学列表(可变)时,你才能体会两者的本质差别。
十、本章边界:今天没讲什么
为避免贪多,Day07 只解决"字符串怎么定义、取字符、切片"这三件事。字符串的格式化输出 (%、.format()、f-string)、编码解码 、以及 find/replace/split/join 等几十个方法,全部放在 Day08。今天你只要记住两件事:
- 字符串是一串不可变的字符,用引号定义;
- 靠"索引取值、切片取段"就能完成大部分基础操作。
把这两点用熟,Day08 的方法学起来会非常顺------那些方法本质上都是"在切片的基础上做加工"。
练习题
- 用三种引号各写一个字符串:含英文双引号的、含英文单引号的、跨三行的,分别打印。
- 给定
s = "PythonProgramming",用切片取出"Python"、"Programming",再把整个字符串反转。 - 用原始字符串写一个 Windows 路径
D:\文档\教材\Python,并用print打印,观察和普通写法的区别。 - 写代码验证"字符串不可变":尝试
s[0]="x"看报什么错,再用+和切片造一个首字母大写的新串。 - 给定
word = "abcdefgh",分别用切片取出偶数位字符和奇数位字符。 - 思考题:
s[::-1]为什么能反转字符串?步长为负时start和end默认指向哪一端?
小结
- 字符串用
'...'、"..."定义,三引号"""..."""可跨行;单双引号等价,按"内部有什么引号就用另一种包"选择。 - 字符串不可变:不能
s[i]=x,所有方法返回新串。 - 转义字符
\n \t \\ \' \"等;原始字符串r"..."所见即所得,适合路径与正则,但末尾不能是单个\。 - 索引从 0 开始,负数从右数(-1 是最后一个);越界索引报 IndexError,但切片越界不报错。
- 切片
s[start:end:step]:左含右不含,省略即到头,[::-1]反转字符串。 len()取长度(中文按字符算 1);+拼接、*重复,都产生新串;字符串不能直接和数字相加。