Python 基础语法(二):字符串与常用操作

0 阅读14分钟

python字符串用来保存文本。姓名、文件路径、网页地址和接口返回的消息,只要内容是文字,在 Python 中通常都会使用字符串处理。

思维导图

在这里插入图片描述

这一章主要讲字符串的创建、索引、切片、常用方法和格式化。字符串看起来简单,不过索引越界、转义字符、split()join() 的用法,以及字符串不可变这些地方都比较容易写错。

在这里插入图片描述

一、创建字符串

Python 中的字符串类型是 str,可以使用单引号、双引号或者三引号创建:

name = 'Ivan'
language = "Python"
message = """这是一个
可以换行的字符串"""

单引号和双引号没有类型上的区别,选择哪一种主要看字符串中包含什么内容。例如,字符串里已经有单引号时,外面使用双引号会方便一些:

message = "I'm learning Python"

如果字符串里有双引号,也可以反过来写:

message = '他说:“今天开始学习 Python。”'

三引号可以保存跨越多行的文本,其中的换行也会成为字符串内容的一部分:

text = """第一行
第二行
第三行"""

print(text)

输出结果为:

第一行
第二行
第三行

空字符串中没有任何字符,但是它仍然是一个字符串对象:

empty_text = ""

print(type(empty_text))
print(len(empty_text))

输出结果为:

<class 'str'>
0

二、转义字符与原始字符串

反斜杠 \ 在字符串中用来表示一些不能直接写出来,或者具有特殊含义的字符。

写法含义
\n换行
\t制表符
\\一个反斜杠
\'单引号
\"双引号
\r回车

例如:

message = "姓名:Ivan\n语言:Python"
print(message)

输出结果为:

姓名:Ivan
语言:Python

1. 路径中的反斜杠

Windows 路径中经常出现反斜杠。如果直接写路径,其中的 \n\t 等组合可能会被当成转义字符:

path = "C:\new\test.txt"
print(path)

这段代码不会按照原路径输出,因为 \n 会换行,\t 会变成制表符。可以把每个反斜杠再转义一次:

path = "C:\\new\\test.txt"

也可以在字符串前加上 r,创建原始字符串:

path = r"C:\new\test.txt"
print(path)

原始字符串会保留大多数反斜杠。不过它不能以单个反斜杠结尾,下面的写法会出现语法错误:

# 错误写法
path = r"C:\new\"

处理路径时,更常见的办法是使用标准库中的 pathlib。这一部分会放到文件操作章节中再讲。

在这里插入图片描述

三、字符串索引

字符串由一个个字符组成,每个字符都有自己的位置,这个位置称为索引。Python 的索引从 0 开始:

text = "Python"

print(text[0])
print(text[1])
print(text[5])

输出结果为:

P
y
n

也可以使用负数索引从右向左读取字符。最后一个字符的索引是 -1

print(text[-1])
print(text[-2])
print(text[-6])

输出结果为:

n
o
P

len() 可以取得字符串的字符数量:

text = "Python"
print(len(text))

结果为 6,所以它能使用的正数索引是 05。访问不存在的位置会引发 IndexError

print(text[6])

中文字符也按照字符数量计算:

text = "学习Python"

print(len(text))
print(text[0])

输出结果为:

8
学

这里的 len() 计算的是字符数量,不是字符串保存到文件以后占用的字节数。

四、字符串切片

索引一次只能取得一个字符,切片可以取出一段字符串。基本写法如下:

字符串[开始位置:结束位置:步长]

切片包含开始位置,不包含结束位置。例如:

text = "Python"

print(text[0:2])
print(text[2:6])

输出结果为:

Py
thon

text[0:2] 取得索引 01,不会取得索引 2。这种规则也常写成“左闭右开”。

1. 省略开始或结束位置

省略开始位置时,默认从字符串开头切:

print(text[:3])

输出 Pyt

省略结束位置时,会一直切到字符串末尾:

print(text[3:])

输出 hon

开始和结束都省略时,会得到完整字符串:

print(text[:])

2. 使用负数索引切片

负数索引也可以放在切片中:

filename = "report.pdf"

print(filename[-3:])
print(filename[:-4])

输出结果为:

pdf
report

3. 设置步长

第三个参数表示每隔几个字符取一次:

text = "0123456789"

print(text[::2])
print(text[1::2])

输出结果为:

02468
13579

步长为负数时,会从右向左取字符。下面的写法可以把字符串倒过来:

text = "Python"
print(text[::-1])

输出结果为 nohtyP

与单个索引不同,切片超出字符串范围通常不会报错:

text = "Python"
print(text[0:100])

结果仍然是 Python。Python 会在字符串实际结束的位置停下来。

在这里插入图片描述

五、字符串是不可变对象

字符串创建以后,其中的字符不能直接修改。下面的代码会出现 TypeError

text = "Python"
text[0] = "J"

如果想把 Python 改成 Jython,需要创建一个新的字符串,再让变量指向它:

text = "Python"
text = "J" + text[1:]

print(text)

字符串方法也是一样。例如,replace() 返回修改后的新字符串,并不会在原字符串上直接修改:

text = "I like Java"
new_text = text.replace("Java", "Python")

print(text)
print(new_text)

输出结果为:

I like Java
I like Python

如果后面的代码要继续使用替换结果,就要接收它的返回值:

text = text.replace("Java", "Python")

在这里插入图片描述

六、字符串的基本运算

1. 拼接字符串

+ 可以拼接多个字符串:

first_name = "Ivan"
last_name = "Chen"
full_name = first_name + " " + last_name

print(full_name)

字符串不能直接和数字拼接:

age = 20

# 错误写法
message = "年龄:" + age

可以先使用 str() 转换,也可以直接使用 f-string:

message1 = "年龄:" + str(age)
message2 = f"年龄:{age}"

2. 重复字符串

* 可以把字符串重复指定次数:

line = "-" * 20
print(line)

3. 判断是否包含

innot in 可以判断字符串中是否包含一段内容:

url = "https://www.python.org"

print("python" in url)
print("java" not in url)

字符串判断区分大小写:

print("Python" in "python.org")

结果为 False

4. 比较字符串

字符串可以使用 ==!=<> 等运算符比较:

print("Python" == "Python")
print("Python" == "python")
print("apple" < "banana")

大小比较会按照字符的 Unicode 编码顺序逐个比较,不等同于汉语拼音、字典顺序或者自然语言中的大小关系。业务代码需要排序中文、忽略大小写或处理不同语言时,通常要增加专门的规则。

七、查找与统计

1. find()rfind()

find() 返回指定内容第一次出现的索引,没有找到时返回 -1

text = "Python is easy, Python is useful"

print(text.find("Python"))
print(text.find("Java"))

输出结果为:

0
-1

rfind() 从右侧开始查找,所以它会返回最后一次出现的位置:

print(text.rfind("Python"))

2. index()rindex()

index() 的结果与 find() 类似,不过没有找到时会引发 ValueError

text = "Python"
print(text.index("th"))

是否使用 find()index(),要看没有找到是不是正常情况。如果没有找到也允许继续运行,find() 通常更方便;如果没有找到说明数据本身有问题,可以使用 index(),再交给异常处理代码处理。

3. count()

count() 用来统计某段内容出现的次数:

text = "banana"
print(text.count("a"))
print(text.count("an"))

输出结果为:

3
2

4. startswith()endswith()

这两个方法用来判断字符串的开头和结尾:

filename = "report.pdf"

print(filename.startswith("report"))
print(filename.endswith(".pdf"))

也可以传入一个元组,同时判断多个候选值:

filename = "photo.png"
is_image = filename.endswith((".jpg", ".jpeg", ".png", ".gif"))

print(is_image)

八、大小写与空白处理

1. 大小写转换

常用的大小写方法如下:

方法作用
lower()转为小写
upper()转为大写
capitalize()首字符大写,其余字符小写
title()每个单词的首字母大写
swapcase()交换大小写
casefold()用于不区分大小写的文本比较
text = "Hello Python"

print(text.lower())
print(text.upper())
print(text.title())

如果只是进行简单的英文大小写转换,lower() 已经够用。需要比较不同语言的文本时,casefold() 处理得更彻底:

left = "Straße"
right = "STRASSE"

print(left.casefold() == right.casefold())

结果为 True

2. 去掉两端字符

strip() 去掉字符串两端的空白,lstrip() 只处理左侧,rstrip() 只处理右侧:

text = "  Python  \n"

print(repr(text.strip()))
print(repr(text.lstrip()))
print(repr(text.rstrip()))

这里使用 repr() 输出,是为了让空格和 \n 更容易看出来。

strip() 也可以接收参数,不过参数表示一组需要从两端删除的字符,并不是完整的前缀或后缀:

text = "www.example.com"
print(text.strip("w.com"))

这段代码会不断删除两端属于 w.com 的字符,结果可能和预想的不一样。删除固定前缀或后缀时,应该使用:

url = "https://example.com"
print(url.removeprefix("https://"))

filename = "report.pdf"
print(filename.removesuffix(".pdf"))

九、替换、拆分与连接

1. replace()

replace() 用来替换字符串中的内容:

text = "Java is useful"
new_text = text.replace("Java", "Python")

print(new_text)

第三个参数可以限制替换次数:

text = "one one one"
print(text.replace("one", "two", 2))

输出结果为 two two one

2. split()

split() 按照指定分隔符把字符串拆成列表:

text = "Python,Java,Go"
languages = text.split(",")

print(languages)

输出结果为:

['Python', 'Java', 'Go']

不传分隔符时,split() 会按照连续的空白字符拆分,并忽略两端空白:

text = "  Python   Java\tGo  "
print(text.split())

输出结果为:

['Python', 'Java', 'Go']

如果明确传入一个空格,规则就不同了,连续空格会产生空字符串:

text = "Python   Java"
print(text.split(" "))

输出结果为:

['Python', '', '', 'Java']

maxsplit 可以限制最多拆分几次:

record = "2026-08-21-error-message"
print(record.split("-", 3))

3. splitlines()

splitlines() 按照换行符拆分多行文本:

text = "第一行\n第二行\n第三行"
print(text.splitlines())

4. join()

join() 把多个字符串连接起来:

languages = ["Python", "Java", "Go"]
text = ", ".join(languages)

print(text)

输出结果为:

Python, Java, Go

调用 join() 的对象是分隔符,因此写法是 "分隔符".join(字符串序列)。列表里如果有整数,需要先转换为字符串:

numbers = [10, 20, 30]

# 错误写法
# text = ",".join(numbers)

text = ",".join(str(number) for number in numbers)
print(text)

这里暂时用到了一个生成器表达式。现阶段只需要知道,它会把列表中的每个数字交给 str() 转换;具体语法会在推导式与生成器章节中再讲。

在这里插入图片描述

十、判断字符串内容

Python 提供了一组以 is 开头的方法,用来判断字符串是否符合某种形式:

方法判断内容
isalpha()是否全部为字母且至少有一个字符
isdigit()是否全部为数字字符且至少有一个字符
isdecimal()是否全部为十进制数字字符
isalnum()是否全部由字母或数字组成
isspace()是否全部为空白字符
islower()是否包含字母且字母都是小写
isupper()是否包含字母且字母都是大写
istitle()是否符合标题大小写形式
print("Python".isalpha())
print("2026".isdigit())
print("Python3".isalnum())
print("   \n".isspace())

这些方法的结果都是布尔值。需要注意,isdigit() 识别的数字字符范围比普通的 09 更广,所以它不能替代完整的数据校验。判断用户输入能不能传给 int(),最稳妥的方式仍然是转换并处理可能出现的 ValueError

十一、字符串格式化

把变量放进字符串时,通常使用 f-string。它从 Python 3.6 开始支持,写法是在字符串前加 f,然后把变量或表达式放入花括号:

name = "Ivan"
age = 20

message = f"姓名:{name},年龄:{age}"
print(message)

花括号中可以写表达式:

price = 19.9
count = 3

print(f"总价:{price * count}")

1. 控制小数位数

price = 19.956

print(f"{price:.2f}")
print(f"{price:.1f}")

输出结果为:

19.96
20.0

2. 千位分隔与百分比

number = 1234567.89
rate = 0.856

print(f"{number:,.2f}")
print(f"{rate:.1%}")

输出结果为:

1,234,567.89
85.6%

3. 对齐与宽度

< 表示左对齐,> 表示右对齐,^ 表示居中:

text = "Python"

print(f"|{text:<10}|")
print(f"|{text:>10}|")
print(f"|{text:^10}|")

输出结果为:

|Python    |
|    Python|
|  Python  |

4. 日期格式

日期对象也可以放进 f-string 中格式化:

from datetime import datetime

now = datetime(2026, 8, 21, 10, 30)
print(f"{now:%Y-%m-%d %H:%M}")

输出结果为:

2026-08-21 10:30

5. str.format()

旧一些的代码中经常能看到 format()

name = "Ivan"
score = 95.5

message = "{} 的成绩是 {:.1f} 分".format(name, score)
print(message)

它仍然可以正常使用,不过新代码在大多数情况下使用 f-string 更直观。%s%d 这种百分号格式化也会出现在旧代码和日志配置中,能够看懂即可。

在这里插入图片描述

十二、字符串与字节

Python 中的 str 保存 Unicode 文本,bytes 保存字节数据。文本写入文件或者通过网络传输时,通常需要按照某种编码转换成字节。

1. 编码

encode() 把字符串转换成字节:

text = "你好,Python"
data = text.encode("utf-8")

print(data)
print(type(data))

2. 解码

decode() 把字节转换回字符串:

text = data.decode("utf-8")
print(text)

编码和解码必须使用相同或者兼容的字符编码。用错误编码解码,可能出现乱码,也可能引发 UnicodeDecodeError

text = "你好"
data = text.encode("utf-8")

# 错误的解码方式
# result = data.decode("ascii")

UTF-8 中,一个中文字符通常占三个字节,所以字符数和字节数可能不同:

text = "你好"

print(len(text))
print(len(text.encode("utf-8")))

输出结果为:

2
6

在这里插入图片描述

十三、综合示例:整理一条商品信息

下面接收一行商品数据,去掉多余空格,再拆出名称、单价和数量,最后计算总价:

raw_text = input("请输入商品信息,格式为 名称,单价,数量:")

parts = raw_text.strip().split(",")

if len(parts) != 3:
    print("输入格式不正确")
else:
    name = parts[0].strip()
    price = float(parts[1].strip())
    count = int(parts[2].strip())
    total = price * count

    print(f"商品:{name}")
    print(f"单价:{price:.2f} 元")
    print(f"数量:{count}")
    print(f"总价:{total:.2f} 元")

输入:

Python 入门书, 59.8, 2

输出结果为:

商品:Python 入门书
单价:59.80 元
数量:2
总价:119.60 元

示例中的 ifelse 属于条件判断。这里先看程序怎样把字符串清理、拆分和转换,条件判断会在下一章详细讲。

十四、常见错误

1. 索引超出范围

text = "Python"
print(text[6])

字符串长度为 6,最后一个有效索引是 5

2. 忘记接收字符串方法的返回值

text = "  Python  "
text.strip()

print(repr(text))

strip() 没有修改原字符串。应该写成:

text = text.strip()

3. 把 strip() 当成删除完整前缀

url = "www.example.com"
result = url.strip("www.")

strip() 按字符集合删除两端内容。删除固定前缀应该使用:

result = url.removeprefix("www.")

4. 混淆 split()join()

text = "Python,Java,Go"
items = text.split(",")       # 字符串拆成列表
result = ",".join(items)     # 列表连接成字符串

5. 在普通字符串中直接写 Windows 路径

path = "C:\new\test.txt"

其中的 \n\t 会被当成转义字符。可以使用双反斜杠、原始字符串,或者后面会讲到的 pathlib

6. 使用字节长度代替字符长度

text = "你好"

print(len(text))
print(len(text.encode("utf-8")))

前者是字符数量,后者是 UTF-8 编码后的字节数量。限制用户名长度时通常看字符数,限制网络报文或文件大小时才会考虑字节数。

十五、练习

练习一:取得文件名和扩展名

给定字符串 "archive.backup.zip",分别取得文件名 "archive.backup" 和扩展名 "zip"。可以先使用 rfind() 找到最后一个点的位置,再配合切片完成。

练习二:隐藏手机号码

输入一个 11 位手机号码,只显示前 3 位和后 4 位,中间使用四个星号代替。例如:

138****5678

练习三:统计单词

给定一段英文文本,去掉两端空格并按照空白拆分,统计其中有多少个单词。

练习四:整理标签

输入字符串 " Python, 数据分析, Web开发 ",去掉每个标签两端的空格,再使用 " | " 连接成下面的形式:

Python | 数据分析 | Web开发

练习五:检查文件类型

判断文件名是否以 .jpg.jpeg.png.gif 结尾。检查时要忽略扩展名的大小写。

这一章把字符串中最常用的内容放在了一起。后面处理输入数据、文件内容和接口结果时,索引、切片、拆分、替换和格式化都会经常用到。