目录

一、Python字符串基础认知

1.1 什么是Python字符串?

1.2 字符串的创建方式

1.2.1 单引号/双引号创建(单行字符串)

1.2.2 三引号创建(多行字符串/注释)

1.2.3 str()函数转换(其他类型转字符串)

1.2.4 原始字符串(避免转义)

1.3 字符串的核心特性:不可变性

为什么Python要设计字符串为不可变?

如何"间接修改"字符串?

1.4 字符串的基本属性:长度与索引

1.4.1 字符串长度(len()函数)

1.4.2 字符串索引(定位字符)

二、Python字符串基础操作

2.1 字符串查找操作

2.1.1 常用查找方法对比

2.1.2 实际应用示例

2.2 字符串判断操作

2.2.1 常用判断方法汇总

2.2.2 实际应用示例

2.3 字符串大小写转换

2.3.1 常用转换方法汇总

2.3.2 实际应用示例

2.4 字符串对齐与填充

2.4.1 常用对齐方法汇总

2.4.2 实际应用示例

2.5 字符串修剪操作

2.5.1 常用修剪方法汇总

2.5.2 实际应用示例

三、Python字符串核心操作(一):切片详解

3.1 切片的基本语法

3.2 基础切片场景

3.2.1 省略参数的常见情况

3.2.2 结合反向索引的切片

3.2.3 指定步长的特殊场景

3.3 高级切片技巧

3.3.1 反向切片实现字符串逆序

3.3.2 切片与字符串不可变性的结合

3.3.3 切片越界的安全处理

3.4 切片的实际应用场景

3.4.1 提取文件扩展名

3.4.2 敏感信息脱敏(手机号、身份证号)

3.4.3 解析固定格式的时间字符串

四、Python字符串核心操作(二):拼接与格式化

4.1 字符串拼接的5种方式

4.1.1 方式1:使用+运算符

4.1.2 方式2:使用*运算符

4.1.3 方式3:使用join()方法

4.1.4 方式4:使用f-string(Python 3.6+)

4.1.5 方式5:使用str.format()方法

4.2 5种拼接方式的对比与选择建议

选择建议:

4.3 字符串格式化的高级技巧

4.3.1 数值格式化(保留小数、百分比、科学计数法)

4.3.2 字符串对齐与填充

4.3.3 日期时间格式化

示例代码1:基础日期时间格式化

示例代码2:带星期和月份名称的格式

示例代码3:f-string直接格式化日期(Python 3.6+)

示例代码4:指定日期的格式化(非当前时间)

五、Python字符串高级操作:替换、分割与正则

5.1 字符串替换的进阶方法

5.1.1 replace()方法的进阶用法

示例1:替换为空字符串(删除指定子串)

示例2:限制替换次数(count参数)

5.1.2 translate()方法:批量替换单个字符

语法细节:

示例1:字典映射替换

示例2:字符对映射替换

示例3:删除指定字符(第三个参数)

5.1.3 replace()与 translate()的对比

5.2 字符串分割的进阶方法

5.2.1 rsplit():从右向左分割

示例1:提取文件路径中的文件名

示例2:限制分割次数(maxsplit)

5.2.2 splitlines():按换行符分割

示例1:基础用法(保留/不保留换行符)

示例2:处理多行文本(如日志、配置文件)

5.2.3 re.split():按多分隔符分割

示例1:按多字符分隔符分割

示例2:保留分割符(用括号分组)

5.3 正则表达式与复杂文本处理

5.3.1 re模块核心函数速览

5.3.2 典型应用场景:提取敏感信息(邮箱、手机号)

场景1:提取文本中的所有手机号

场景2:提取文本中的所有邮箱

5.3.3 典型应用场景:批量替换与文本清洗

场景1:去除文本中的所有HTML标签

场景2:统一文本中的日期格式

六、字符串操作性能优化与常见问题

6.1 字符串操作性能优化技巧

6.1.1 避免频繁使用+拼接大量字符串

示例对比:

6.1.2 优先使用f-string而非str.format()

示例对比:

6.1.3 编译正则表达式(re.compile())

示例对比:

6.1.4 用startswith()/endswith()替代切片判断

示例对比:

6.2 字符串操作常见问题与解决方案

6.2.1 问题1:索引越界(IndexError)

6.2.2 问题2:字符串拼接类型错误(TypeError)

6.2.3 问题3:strip()无法去除中间空白字符

七、总结与实战建议

7.1 核心知识点梳理

7.2 实战建议


在Python编程中,字符串是最基础且高频使用的数据类型之一,无论是日常脚本开发、数据清洗,还是Web应用中的文本处理,都离不开字符串操作。掌握字符串的核心用法,能显著提升代码效率与可读性。本文将从字符串的基本概念出发,系统讲解创建、访问、修改等基础操作,深入剖析切片、拼接等核心技巧,最后结合实战案例展示高级应用,帮助读者全面掌握Python字符串操作。

一、Python字符串基础认知

在学习具体操作前,我们首先需要明确字符串的本质与核心特性,这是理解后续操作的关键。

1.1 什么是Python字符串?

字符串(String)是由零个或多个字符组成的不可变序列,可包含字母、数字、符号、空格及各类Unicode字符(如中文、日文)。在Python中,字符串以Unicode编码存储,天然支持多语言处理,这也是Python在文本处理领域广泛应用的重要原因。

例如:

  • 单字符字符串:"a""1""中"

  • 多字符字符串:"Python""2025编程""Hello World!"

  • 空字符串:""(零个字符组成,长度为0)

1.2 字符串的创建方式

Python提供了多种灵活的字符串创建方式,可根据场景需求选择最合适的方法:

1.2.1 单引号/双引号创建(单行字符串)

使用单引号 ' '或双引号 " "包裹字符,适用于创建单行字符串。两种方式功能一致,主要区别在于嵌套引号时无需转义:

  • 字符串内包含双引号时,用单引号定义

  • 字符串内包含单引号时,用双引号定义

示例代码:

# 单引号创建(字符串含双引号)
str1 = 'He said: "I love Python"'
print(str1)  # 输出:He said: "I love Python"

# 双引号创建(字符串含单引号)
str2 = "It's a sunny day"
print(str2)  # 输出:It's a sunny day

# 单/双引号嵌套错误示例(需转义,不推荐)
# str3 = 'He said: 'I love Python''  # 报错:SyntaxError
# 正确写法(转义):str3 = 'He said: \'I love Python\''
1.2.2 三引号创建(多行字符串/注释)

使用三个连续的单引号 ''' '''或双引号 """ """,支持直接创建多行字符串(保留换行符),也可作为多行注释(需注意:作为注释时不会被解释器执行,仅作代码说明)。

示例代码:

# 三引号创建多行字符串(保留换行格式)
str4 = '''这是第一行
这是第二行
这是第三行'''
print(str4)
# 输出:
# 这是第一行
# 这是第二行
# 这是第三行

# 三引号包含多种引号(无需转义)
str5 = """Python支持:
1. 单引号 ' 
2. 双引号 "
3. 三引号 """
print(str5)

# 三引号作为多行注释(不会被执行)
"""
这是一段多行注释
用于说明下方代码的功能:
- 定义一个字符串
- 打印字符串长度
"""
str6 = "Test"
print(len(str6))  # 输出:4
1.2.3 str()函数转换(其他类型转字符串)

通过内置函数 str()可将整数、浮点数、布尔值、列表等其他数据类型转换为字符串,是数据类型交互的常用手段。

示例代码:

# 整数转字符串
num = 123
str_num = str(num)
print(type(str_num), str_num)  # 输出:<class 'str'> 123

# 浮点数转字符串
float_val = 3.14159
str_float = str(float_val)
print(type(str_float), str_float)  # 输出:<class 'str'> 3.14159

# 布尔值转字符串(注意:True→"True",False→"False")
bool_val = True
str_bool = str(bool_val)
print(type(str_bool), str_bool)  # 输出:<class 'str'> True

# 列表转字符串(保留列表格式符号)
list_val = [1, 2, 3]
str_list = str(list_val)
print(type(str_list), str_list)  # 输出:<class 'str'> [1, 2, 3]
1.2.4 原始字符串(避免转义)

在字符串前加 rR,表示原始字符串,其中的转义字符(如 \n换行、\t制表符、``路径分隔符)会被当作普通字符处理,常用于文件路径、正则表达式等场景。

示例代码:

# 普通字符串(\n 被解析为换行)
normal_str = "C:\new_folder\test.txt"
print(normal_str)
# 输出(格式错乱):
# C:
# ew_folder	est.txt

# 原始字符串(\n 被当作普通字符)
raw_str = r"C:\new_folder\test.txt"
print(raw_str)  # 输出:C:\new_folder\test.txt

# 正则表达式中的原始字符串(避免多重转义)
import re
# 普通字符串需双重转义(\d 表示数字,需写为 \\d)
pattern1 = "\\d+"
# 原始字符串直接写 \d(更简洁)
pattern2 = r"\d+"
text = "Python 3.12"
print(re.findall(pattern1, text))  # 输出:['3', '12']
print(re.findall(pattern2, text))  # 输出:['3', '12']

1.3 字符串的核心特性:不可变性

不可变性是Python字符串最关键的特性——字符串一旦创建,其内部的字符序列就无法被直接修改(如替换某个字符、删除某个字符)。若强行修改,Python会抛出 TypeError错误。

示例代码:

str_test = "Hello"
# 尝试修改索引0的字符(H→h),报错
str_test[0] = "h"  
# 错误信息:TypeError: 'str' object does not support item assignment
为什么Python要设计字符串为不可变?
  1. 安全性:不可变对象在多线程环境下无需加锁,避免并发修改导致的数据混乱;

  2. 哈希稳定性:不可变对象可作为字典的键(Key)或集合(Set)的元素(可变对象如列表无法作为字典键);

  3. 性能优化:Python可对不可变字符串进行缓存(如小字符串缓存池),减少内存占用。

如何"间接修改"字符串?

虽然字符串不可变,但可通过创建新字符串的方式间接实现"修改"效果,常用手段包括:

  • 切片 + 拼接

  • 字符串替换方法(replace()

  • 转为列表修改后再拼接

示例代码:

str_test = "Hello"
# 1. 切片 + 拼接(修改首字符为h)
new_str1 = "h" + str_test[1:]
print(new_str1)  # 输出:hello

# 2. replace()方法(替换子串)
new_str2 = str_test.replace("Hello", "Hello World")
print(new_str2)  # 输出:Hello World

# 3. 转为列表修改(适合多字符修改)
char_list = list(str_test)
char_list[4] = "o"  # 将最后一个字符o改为O(原字符为o,此处示例改为O)
new_str3 = "".join(char_list)
print(new_str3)  # 输出:HellO

1.4 字符串的基本属性:长度与索引

掌握字符串的长度和索引,是后续访问、切片等操作的基础。

1.4.1 字符串长度(len()函数)

使用内置函数 len(str)可获取字符串的长度(即字符的个数),空字符串的长度为0。

示例代码:

# 普通字符串
str1 = "Python"
print(len(str1))  # 输出:6(6个字符)

# 含空格和符号的字符串
str2 = "Hello, Python!"
print(len(str2))  # 输出:13(包含逗号、空格、感叹号)

# 空字符串
str3 = ""
print(len(str3))  # 输出:0

# 多行字符串(换行符\n算1个字符)
str4 = '''Line1
Line2'''
print(len(str4))  # 输出:9(Line1(5) + \n(1) + Line2(4) = 10?实际计算:Line1为5字符,\n为1,Line2为4,共10?需注意实际字符数,此处以实际运行结果为准)
1.4.2 字符串索引(定位字符)

字符串中的每个字符都有唯一的索引(Index),用于定位字符位置。Python支持两种索引方式:正向索引和反向索引,极大提升了定位灵活性。

以字符串 s = "abcde"为例,两种索引的对应关系如下表:

字符

a

b

c

d

e

正向索引

0

1

2

3

4

反向索引

-5

-4

-3

-2

-1

  • 正向索引:从字符串开头(第一个字符)开始,索引值从 0递增;

  • 反向索引:从字符串结尾(最后一个字符)开始,索引值从 -1递减。

通过索引访问字符的语法为 str[index],示例代码:

s = "abcde"
# 正向索引访问
print(s[0])  # 输出:a(第一个字符)
print(s[2])  # 输出:c(第三个字符)

# 反向索引访问
print(s[-1])  # 输出:e(最后一个字符)
print(s[-3])  # 输出:c(倒数第三个字符)

# 索引越界报错(正向最大索引为 len(s)-1,反向最小索引为 -len(s))
# print(s[5])  # 报错:IndexError: string index out of range
# print(s[-6])  # 报错:IndexError: string index out of range

二、Python字符串基础操作

基础操作是字符串处理的"基本功",涵盖查找、判断、大小写转换、对齐填充、修剪等高频功能,掌握这些操作能应对大部分简单文本处理场景。

2.1 字符串查找操作

查找操作用于确定字符或子串(Substring)在目标字符串中的位置或出现次数,常用方法有 find()rfind()index()rindex()count()

2.1.1 常用查找方法对比

方法

语法

功能描述

核心特点

示例

结果

find()

str.find(sub, start=0, end=len(str))

[start, end)区间(左闭右开)查找 sub首次出现的索引;未找到返回 -1

未找到不报错,返回 -1

"abcabc".find("ab", 1, 5)

3

rfind()

str.rfind(sub, start=0, end=len(str))

[start, end)区间反向查找 sub末次出现的索引;未找到返回 -1

反向查找,未找到返回 -1

"abcabc".rfind("ab")

3

index()

str.index(sub, start=0, end=len(str))

find()功能一致,但未找到 sub时抛出 ValueError

未找到报错,适合必须找到的场景

"abcabc".index("cd")

报错

rindex()

str.rindex(sub, start=0, end=len(str))

rfind()功能一致,但未找到 sub时抛出 ValueError

反向查找,未找到报错

"abcabc".rindex("bc")

4

count()

str.count(sub, start=0, end=len(str))

统计 sub[start, end)区间内出现的次数;未找到返回 0

仅统计次数,不返回索引

"abcabc".count("ab")

2

2.1.2 实际应用示例
# 定义目标字符串
s = "Python is a powerful language. Python is easy to learn. Python is fun!"

# 1. 查找首次出现"Python"的位置
first_python = s.find("Python")
print("首次出现'Python'的索引:", first_python)  # 输出:0

# 2. 从索引10开始查找"Python"(跳过第一个"Python")
second_python = s.find("Python", 10)
print("从索引10开始首次出现'Python'的索引:", second_python)  # 输出:29

# 3. 反向查找"Python"(末次出现位置)
last_python = s.rfind("Python")
print("末次出现'Python'的索引:", last_python)  # 输出:54

# 4. 统计"is"出现的次数
is_count = s.count("is")
print("'is'出现的次数:", is_count)  # 输出:3

# 5. 统计"Python"在索引0-30区间内的次数
python_count = s.count("Python", 0, 30)
print("索引0-30内'Python'出现的次数:", python_count)  # 输出:2

# 6. 查找不存在的子串(find返回-1,index报错)
no_sub = s.find("Java")
print("查找'Java'的结果:", no_sub)  # 输出:-1
# s.index("Java")  # 取消注释会报错:ValueError: substring not found

2.2 字符串判断操作

判断操作用于检验字符串是否满足特定条件(如是否全为字母、是否以某个子串开头),返回布尔值 TrueFalse,常用于数据校验(如手机号格式初步判断、用户输入合法性检查)。

2.2.1 常用判断方法汇总

方法

语法

功能描述

示例

结果

isalpha()

str.isalpha()

若字符串所有字符均为字母(含Unicode字母如中文、日文)且非空,返回 True

"Python".isalpha()
"Python123".isalpha()

True
False

isdigit()

str.isdigit()

若字符串所有字符均为数字(含Unicode数字如①、Ⅱ)且非空,返回 True

"12345".isdigit()
"3.14".isdigit()

True
False

isalnum()

str.isalnum()

若字符串所有字符均为字母或数字且非空,返回 True

"Python123".isalnum()
"Python!".isalnum()

True
False

isspace()

str.isspace()

若字符串所有字符均为空白字符(空格、\t\n等)且非空,返回 True

" \t\n".isspace()
" a ".isspace()

True
False

islower()

str.islower()

若字符串所有字母均为小写且至少有一个字母,返回 True

"python".islower()
"Python".islower()

True
False

isupper()

str.isupper()

若字符串所有字母均为大写且至少有一个字母,返回 True

"PYTHON".isupper()
"Python".isupper()

True
False

istitle()

str.istitle()

若字符串为标题格式(每个单词首字母大写,其余小写)且非空,返回 True

"Python Is Fun".istitle()
"python is fun".istitle()

True
False

startswith()

str.startswith(prefix, start=0, end=len(str))

判断 [start, end)区间是否以 prefix开头,返回 True/Falseprefix可为元组)

"Python".startswith("Py")
"Python".startswith(("Py", "Ja"))

True
True

endswith()

str.endswith(suffix, start=0, end=len(str))

判断 [start, end)区间是否以 suffix结尾,返回 True/Falsesuffix可为元组)

"report.pdf".endswith(".pdf")
"report.pdf".endswith((".txt", ".pdf"))

True
True

2.2.2 实际应用示例
# 定义测试字符串
s1 = "Python"          # 纯字母(混合大小写)
s2 = "123456"          # 纯数字
s3 = "Python123"       # 字母+数字
s4 = "   \t\n"         # 纯空白字符
s5 = "python is fun"   # 纯小写字母(含空格)
s6 = "PYTHON IS FUN"   # 纯大写字母(含空格)
s7 = "Python Is Fun"   # 标题格式
s8 = "report.pdf"      # 文件名(含后缀)
s9 = "2025-08-22"      # 日期字符串

# 1. 判断是否为纯字母
print(s1.isalpha())          # 输出:True
print("中文测试".isalpha())  # 输出:True(Unicode字母)
print(s3.isalpha())          # 输出:False(含数字)

# 2. 判断是否为纯数字
print(s2.isdigit())          # 输出:True
print("①②③".isdigit())    # 输出:True(Unicode数字)
print("3.14".isdigit())      # 输出:False(含小数点)

# 3. 判断是否为字母或数字
print(s3.isalnum())          # 输出:True
print(s8.isalnum())          # 输出:False(含小数点)

# 4. 判断是否为纯空白字符
print(s4.isspace())          # 输出:True
print("  a  ".isspace())     # 输出:False(含非空白字符)

# 5. 判断大小写
print(s5.islower())          # 输出:True
print(s6.isupper())          # 输出:True
print(s1.islower())          # 输出:False(含大写字母)

# 6. 判断标题格式
print(s7.istitle())          # 输出:True
print("Python is Fun".istitle())  # 输出:False("is"首字母小写)

# 7. 判断开头/结尾(支持多前缀/后缀)
print(s8.startswith(("rep", "doc")))  # 输出:True(以"rep"开头)
print(s8.endswith((".pdf", ".txt")))  # 输出:True(以".pdf"结尾)
print(s9.startswith("2024"))          # 输出:False(年份为2025)

2.3 字符串大小写转换

大小写转换常用于文本标准化处理(如统一用户名格式、关键词匹配前预处理),Python提供了5种常用转换方法,覆盖大部分场景。

2.3.1 常用转换方法汇总

方法

语法

功能描述

示例

结果

lower()

str.lower()

将字符串所有字母转为小写,非字母字符不变

"Hello Python WORLD".lower()

"hello python world"

upper()

str.upper()

将字符串所有字母转为大写,非字母字符不变

"Hello Python WORLD".upper()

"HELLO PYTHON WORLD"

capitalize()

str.capitalize()

将字符串首字母转为大写,其余字母转为小写

"hello python WORLD".capitalize()

"Hello python world"

title()

str.title()

将字符串转为标题格式(每个单词首字母大写,其余小写)

"hello python world".title()

"Hello Python World"

swapcase()

str.swapcase()

交换字符串的大小写(小写→大写,大写→小写)

"Hello Python WORLD".swapcase()

"hELLO pYTHON world"

2.3.2 实际应用示例
# 定义原始字符串
s = "Hello Python WORLD! 123"

# 1. 转为全小写
print(s.lower())  # 输出:hello python world! 123

# 2. 转为全大写
print(s.upper())  # 输出:HELLO PYTHON WORLD! 123

# 3. 首字母大写(其余小写)
print(s.capitalize())  # 输出:Hello python world! 123

# 4. 转为标题格式
print(s.title())  # 输出:Hello Python World! 123("123"不影响单词判断)

# 5. 交换大小写
print(s.swapcase())  # 输出:hELLO pYTHON world! 123

# 实际应用:关键词不区分大小写匹配
keyword = "python"
user_input = "I love PYTHON"
# 统一转为小写后匹配
if keyword.lower() == user_input.split()[-1].lower():
    print("关键词匹配成功!")
else:
    print("关键词匹配失败!")
# 输出:关键词匹配成功!

2.4 字符串对齐与填充

对齐操作可使字符串在指定长度内按需求(左对齐、右对齐、居中对齐)排列,常配合填充字符(如空格、*=)使用,多用于格式化输出(如表格展示、日志排版)。

2.4.1 常用对齐方法汇总

方法

语法

功能描述

示例

结果

ljust()

str.ljust(width, fillchar=' ')

左对齐,总长度为 width,不足部分用 fillchar填充(默认空格)

"Python".ljust(10, "-")

"Python----"

rjust()

str.rjust(width, fillchar=' ')

右对齐,总长度为 width,不足部分用 fillchar填充(默认空格)

"Python".rjust(10, "*")

"****Python"

center()

str.center(width, fillchar=' ')

居中对齐,总长度为 width,不足部分用 fillchar填充(默认空格)

"Python".center(10, "=")

"==Python=="

zfill()

str.zfill(width)

左侧用 0填充,总长度为 width;若字符串以 +/-开头,0填充在符号后

"-123".zfill(6)

"-00123"

注:若 width小于等于原字符串长度,方法直接返回原字符串(无需填充)。

2.4.2 实际应用示例
# 定义原始字符串
s = "Python"
num_str1 = "123"
num_str2 = "-456"
num_str3 = "+789"

# 1. 左对齐(长度10,用"-"填充)
print(s.ljust(10, "-"))  # 输出:Python----
print(s.ljust(5, "-"))   # 输出:Python(width<原长度,返回原字符串)

# 2. 右对齐(长度10,用"*"填充)
print(s.rjust(10, "*"))  # 输出:****Python
print(num_str1.rjust(8, "0"))  # 输出:00000123(数字右对齐,左侧补0)

# 3. 居中对齐(长度10,用"="填充)
print(s.center(10, "="))  # 输出:==Python==
print("Hello".center(9, " "))  # 输出:  Hello  (两侧各2个空格)

# 4. 0填充(zfill,常用于数字格式化)
print(num_str1.zfill(6))  # 输出:000123
print(num_str2.zfill(6))  # 输出:-00456(0在负号后)
print(num_str3.zfill(6))  # 输出:+00789(0在正号后)

# 实际应用:格式化输出表格
print("姓名".ljust(10) + "年龄".ljust(5) + "城市".ljust(10))
print("-" * 25)
print("张三".ljust(10) + "25".ljust(5) + "北京".ljust(10))
print("李四".ljust(10) + "30".ljust(5) + "上海".ljust(10))
# 输出:
# 姓名        年龄   城市      
# -------------------------
# 张三        25    北京      
# 李四        30    上海

2.5 字符串修剪操作

修剪操作用于去除字符串首尾的指定字符(默认去除空白字符,如空格、\t\n),常用于用户输入清洗(如去除输入内容前后的多余空格)。

2.5.1 常用修剪方法汇总

方法

语法

功能描述

示例

结果

strip()

str.strip(chars=None)

去除字符串首尾的 chars字符;charsNone时去除空白字符

"###Python###".strip("#")

"Python"

lstrip()

str.lstrip(chars=None)

去除字符串左侧的 chars字符;charsNone时去除空白字符

" \tPython".lstrip()

"Python"

rstrip()

str.rstrip(chars=None)

去除字符串右侧的 chars字符;charsNone时去除空白字符

"Python\n ".rstrip()

"Python"

注:chars是字符集合,而非子串——例如 strip("abc")会去除首尾所有 abc字符,无论顺序。

2.5.2 实际应用示例
# 1. 去除空白字符(默认情况)
s1 = "  \tPython is fun\n  "  # 左侧:2空格+1制表符;右侧:1换行符+2空格
print("原始字符串:", repr(s1))  # 输出:'  \tPython is fun\n  '(repr()显示特殊字符)
print("strip后:", repr(s1.strip()))  # 输出:'Python is fun'
print("lstrip后:", repr(s1.lstrip()))  # 输出:'Python is fun\n  '
print("rstrip后:", repr(s1.rstrip()))  # 输出:'  \tPython is fun'

# 2. 去除指定字符(chars为字符集合)
s2 = "###Python###"
print(s2.strip("#"))  # 输出:Python(去除首尾#)

s3 = "abcPythoncba"
print(s3.strip("abc"))  # 输出:Python(去除首尾所有a、b、c,无论顺序)

s4 = "123Hello321"
print(s4.lstrip("12"))  # 输出:3Hello321(左侧去除1和2,保留3)
print(s4.rstrip("12"))  # 输出:123Hello3(右侧去除1和2,保留3)

# 实际应用:清洗用户输入
user_input = input("请输入用户名:")  # 假设用户输入:"  admin123  "
cleaned_input = user_input.strip()
print("清洗后的用户名:", cleaned_input)  # 输出:admin123

三、Python字符串核心操作(一):切片详解

字符串切片是Python中极具特色的操作,它能快速、灵活地提取字符串的子串,无需循环遍历,代码简洁高效。掌握切片技巧,能极大提升字符串处理效率。

3.1 切片的基本语法

切片的完整语法为:

str[start:end:step]

其中三个参数的含义、默认值及取值范围如下表:

参数

含义

默认值

取值范围

说明

start

切片的起始索引(包含该索引对应的字符)

0(字符串开头)

正整数(正向索引)、负整数(反向索引)

决定从哪个位置开始切片

end

切片的结束索引(不包含该索引对应的字符,左闭右开原则)

len(str)(字符串结尾)

正整数(正向索引)、负整数(反向索引)

决定切片到哪个位置结束

step

切片的步长(即每隔几个字符取一个)

1

正整数(从左到右切片)、负整数(从右到左切片)

决定切片的方向和间隔

核心原则:

  1. 左闭右开:切片结果包含 start对应的字符,不包含 end对应的字符;

  2. 参数可选:三个参数均可省略,省略时使用默认值;

  3. 索引灵活:支持正向索引和反向索引混合使用;

  4. 步长控制方向:step>0从左到右切片,step<0从右到左切片(反向切片)。

3.2 基础切片场景

以下以字符串 s = "0123456789"(索引0-9)为例,讲解常见的基础切片场景。

3.2.1 省略参数的常见情况

通过省略不同参数,可实现不同的切片需求,是切片操作中最常用的形式:

切片表达式

省略参数

含义

结果

s[2:5]

step(默认1)

从索引2到5(不含5),步长1

"234"

s[:5]

start(默认0)、step(默认1)

从开头到索引5(不含5),步长1

"01234"

s[5:]

end(默认10)、step(默认1)

从索引5到结尾,步长1

"56789"

s[:]

start(0)、end(10)、step(1)

复制整个字符串

"0123456789"

s[::2]

start(0)、end(10)

从开头到结尾,步长2(每隔1个字符取1个)

"02468"

s[1::2]

end(10)

从索引1到结尾,步长2

"13579"

示例代码:

s = "0123456789"  # 索引0-9

# 1. 省略step(默认1)
print(s[2:5])  # 输出:234(索引2、3、4)

# 2. 省略start(默认0)
print(s[:5])   # 输出:01234(索引0-4)

# 3. 省略end(默认10)
print(s[5:])   # 输出:56789(索引5-9)

# 4. 省略start和end(复制字符串)
print(s[:])    # 输出:0123456789

# 5. 省略start和end,指定step
print(s[::2])  # 输出:02468(索引0、2、4、6、8)
print(s[1::2]) # 输出:13579(索引1、3、5、7、9)
3.2.2 结合反向索引的切片

反向索引(从-1开始)可快速定位字符串末尾的字符,结合切片能简化"从末尾截取"的操作,尤其适合处理长字符串:

切片表达式

含义

结果

s[-5:-2]

从索引-5(字符"5")到-2(字符"8",不含8),步长1

"567"

s[:-2]

从开头到索引-2(字符"8",不含8),步长1

"01234567"

s[-5:]

从索引-5(字符"5")到结尾,步长1

"56789"

s[-8:-3:2]

从索引-8(字符"2")到-3(字符"7",不含7),步长2

"246"

示例代码:

s = "0123456789"

# 1. 反向索引定位区间
print(s[-5:-2])  # 输出:567(索引-5→5,-4→6,-3→7;不含-2→8)

# 2. 从开头到倒数第2个字符(不含)
print(s[:-2])   # 输出:01234567(不含索引-2→8和-1→9)

# 3. 从倒数第5个字符到结尾
print(s[-5:])   # 输出:56789(索引-5→5到-1→9)

# 4. 反向索引+指定步长
print(s[-8:-3:2])  # 输出:246(索引-8→2,-6→4,-4→6;步长2)
3.2.3 指定步长的特殊场景

步长 step不仅决定字符间隔,还决定切片方向,需注意 step正负与 startend索引的匹配关系:

  • step>0(从左到右):需满足 start < end,否则返回空字符串;

  • step<0(从右到左):需满足 start > end,否则返回空字符串。

示例代码:

s = "0123456789"

# 1. step为正,start > end → 空字符串
print(s[5:2])  # 输出:""(从左到右,但start=5 > end=2,无匹配)

# 2. step为3(每隔2个字符取1个)
print(s[::3])  # 输出:0369(索引0、3、6、9)
print(s[2:8:3]) # 输出:25(索引2→2,5→5;下一个索引8超出end=8,不含)

# 3. step为负(从右到左切片)
print(s[8:2:-2])  # 输出:864(索引8→8,6→6,4→4;步长-2)
print(s[5:0:-1])  # 输出:54321(索引5→5到1→1;不含0→0)
print(s[2:8:-1])  # 输出:""(step为负,start=2 < end=8,无匹配)

3.3 高级切片技巧

3.3.1 反向切片实现字符串逆序

step=-1且省略 startend时,切片会从字符串末尾到开头遍历所有字符,这是Python中最简洁高效的字符串逆序方法。

示例代码:

# 1. 普通字符串逆序
s1 = "Python"
print(s1[::-1])  # 输出:nohtyP

# 2. 数字字符串逆序
s2 = "123456"
print(s2[::-1])  # 输出:654321

# 3. 带符号字符串逆序
s3 = "Hello-World"
print(s3[::-1])  # 输出:dlroW-olleH

# 4. 部分逆序(从索引3到0,步长-1)
s4 = "0123456789"
print(s4[3:0:-1])  # 输出:321(索引3→3,2→2,1→1;不含0→0)
print(s4[-1:-4:-1]) # 输出:987(索引-1→9,-2→8,-3→7;不含-4→6)
3.3.2 切片与字符串不可变性的结合

由于字符串不可变,无法直接修改字符,但通过"切片+拼接"可间接实现"修改"、"插入"、"删除"字符的效果,这是处理字符串不可变性的核心技巧。

示例代码:

# 原始字符串
s = "Hello World"  # 索引0-10

# 1. 修改字符(将索引5的空格改为"-")
new_s1 = s[:5] + "-" + s[6:]
print(new_s1)  # 输出:Hello-World

# 2. 插入字符(在索引5处插入" Python")
new_s2 = s[:5] + " Python" + s[5:]
print(new_s2)  # 输出:Hello Python World

# 3. 删除字符(删除索引3-5的字符"lo ")
new_s3 = s[:3] + s[6:]
print(new_s3)  # 输出:HelWorld

# 4. 替换子串(将"World"改为"Python")
new_s4 = s[:6] + "Python"
print(new_s4)  # 输出:Hello Python
3.3.3 切片越界的安全处理

与单个索引访问不同,切片操作中若 startend超出字符串的有效索引范围,Python不会抛出 IndexError,而是自动将其调整为最接近的有效索引,这种"容错"机制让切片更安全。

示例代码:

s = "0123456789"  # 有效索引:正向0-9,反向-10到-1

# 1. start超出最大正向索引(10 > 9)
print(s[10:12])  # 输出:""(start=10自动调整为10(len(s)=10),end=12调整为10,区间为空)

# 2. end超出最小反向索引(-15 < -10)
print(s[:-15])   # 输出:""(end=-15自动调整为0,start=0,区间为空)

# 3. start和end均超出范围
print(s[-15:15]) # 输出:0123456789(start=-15调整为0,end=15调整为10,即整个字符串)

# 4. 反向切片时超出范围
print(s[15:5:-1]) # 输出:9876(start=15调整为9,end=5调整为5,步长-1,索引9→9到6→6)

3.4 切片的实际应用场景

切片在实际开发中应用广泛,以下列举几个典型场景,帮助读者建立"问题-方案"映射。

3.4.1 提取文件扩展名

通过 rfind(".")找到最后一个 .的索引,再结合切片提取扩展名,适用于单扩展名(如 .pdf)和多扩展名(如 .tar.gz)文件。

示例代码:

def get_file_extension(filename):
    """提取文件扩展名"""
    # 找到最后一个"."的索引
    dot_index = filename.rfind(".")
    if dot_index == -1:  # 无扩展名
        return ""
    # 切片提取扩展名(从"."到结尾)
    return filename[dot_index:]

# 测试
print(get_file_extension("report.pdf"))    # 输出:.pdf
print(get_file_extension("data.tar.gz"))   # 输出:.gz(提取最后一个扩展名)
print(get_file_extension("readme"))        # 输出:""(无扩展名)
print(get_file_extension("image.png.bak")) # 输出:.bak
3.4.2 敏感信息脱敏(手机号、身份证号)

对敏感信息进行脱敏处理,例如隐藏手机号中间4位、身份证号中间8位,仅保留首尾部分,保护用户隐私。

示例代码:

def mask_phone(phone):
    """手机号脱敏:隐藏中间4位"""
    if len(phone) != 11 or not phone.isdigit():
        return "无效手机号"
    # 保留前3位和后4位,中间用"****"代替
    return phone[:3] + "****" + phone[-4:]

def mask_id(id_card):
    """身份证号脱敏:隐藏中间8位"""
    if len(id_card) != 18:
        return "无效身份证号"
    # 保留前6位和后4位,中间用"********"代替
    return id_card[:6] + "********" + id_card[-4:]

# 测试
print(mask_phone("13812345678"))  # 输出:138****5678
print(mask_phone("123456789"))    # 输出:无效手机号
print(mask_id("110101199001011234"))  # 输出:110101********1234
print(mask_id("11010119900101123"))   # 输出:无效身份证号
3.4.3 解析固定格式的时间字符串

对于格式固定的时间字符串(如 YYYY-MM-DD HH:MM:SS),无需使用复杂的正则表达式,通过切片可快速提取年、月、日、时、分、秒等信息。

示例代码:

def parse_time(time_str):
    """解析时间字符串:YYYY-MM-DD HH:MM:SS"""
    # 验证格式(简化版,实际项目可结合正则)
    if len(time_str) != 19 or time_str[4] != "-" or time_str[7] != "-" or time_str[10] != " " or time_str[13] != ":" or time_str[16] != ":":
        return "无效时间格式"
    # 切片提取各部分
    year = time_str[:4]
    month = time_str[5:7]
    day = time_str[8:10]
    hour = time_str[11:13]
    minute = time_str[14:16]
    second = time_str[17:19]
    return {
        "year": year,
        "month": month,
        "day": day,
        "hour": hour,
        "minute": minute,
        "second": second
    }

# 测试
time_info = parse_time("2025-08-22 15:30:45")
print(time_info)
# 输出:
# {
#     'year': '2025', 
#     'month': '08', 
#     'day': '22', 
#     'hour': '15', 
#     'minute': '30', 
#     'second': '45'
# }

print(parse_time("2025/08/22 15:30:45"))  # 输出:无效时间格式

四、Python字符串核心操作(二):拼接与格式化

字符串拼接是将多个字符串组合为一个字符串的操作,而字符串格式化是按指定格式插入数据(如变量、表达式结果)并生成新字符串。二者在日志输出、数据展示、模板生成等场景中高频使用,掌握其用法能显著提升代码的可读性与效率。

4.1 字符串拼接的5种方式

Python提供了多种字符串拼接方式,各有优缺点,需根据拼接数量、性能需求选择合适的方式。

4.1.1 方式1:使用+运算符

+是最直观的拼接方式,适用于少量字符串的拼接,语法为 str1 + str2 + ... + strn

特点:

  • 优点:语法简单,易于理解,适合拼接2-3个字符串;

  • 缺点:由于字符串不可变,每次 +拼接都会创建新字符串,当拼接大量字符串(如10万次)时,会产生大量临时对象,导致效率极低。

示例代码:

# 1. 普通字符串拼接
str1 = "Hello"
str2 = "Python"
result1 = str1 + " " + str2
print(result1)  # 输出:Hello Python

# 2. 字符串与其他数据类型拼接(需先转为字符串)
num = 2025
bool_val = True
result2 = str1 + " " + str(num) + "! " + "Is it fun? " + str(bool_val)
print(result2)  # 输出:Hello 2025! Is it fun? True

# 3. 错误示例(未转换数据类型)
# result3 = str1 + " " + num  # 报错:TypeError: can only concatenate str (not "int") to str
4.1.2 方式2:使用*运算符

*用于将字符串重复指定次数并拼接,语法为 str * nn为非负整数)。

特点:

  • 优点:简洁高效,仅需一次操作即可完成重复拼接,适合生成固定格式的分隔符、填充符;

  • 缺点:仅适用于重复拼接同一字符串,无法拼接不同内容的字符串。

示例代码:

# 1. 重复拼接
str3 = "ab"
result1 = str3 * 3
print(result1)  # 输出:ababab

# 2. n=0(返回空字符串)
result2 = str3 * 0
print(result2)  # 输出:""

# 3. n=1(返回原字符串)
result3 = str3 * 1
print(result3)  # 输出:ab

# 4. 实际应用:生成分隔线、填充符
separator = "-" * 50
print(separator)  # 输出:--------------------------------------------------
print("日志内容:程序启动成功")
print(separator)

# 生成固定长度的填充符
fill = "=" * 10
print(fill + " 数据开始 " + fill)  # 输出:========== 数据开始 ==========
4.1.3 方式3:使用join()方法

join()是Python中拼接大量字符串的首选方式,语法为 str_sep.join(iterable),其中:

  • str_sep:分隔符(拼接后插入到每个元素之间);

  • iterable:可迭代对象(如列表、元组、字符串等,元素必须全为字符串类型)。

特点:

  • 优点:仅创建一次新字符串,效率极高(比 +快几十到上百倍),适合拼接列表、元组中的大量字符串;

  • 缺点:需先将非字符串元素转为字符串,且需构造可迭代对象。

示例代码:

# 1. 列表元素拼接(元素全为字符串)
str_list = ["Hello", "Python", "2025"]
result1 = " ".join(str_list)  # 以空格为分隔符
print(result1)  # 输出:Hello Python 2025

# 2. 元组元素拼接(以逗号为分隔符)
str_tuple = ("Apple", "Banana", "Orange")
result2 = ", ".join(str_tuple)
print(result2)  # 输出:Apple, Banana, Orange

# 3. 非字符串元素拼接(需先转换)
num_list = [1, 2, 3, 4, 5]
# 方法1:列表推导式转换
result3 = "-".join(str(num) for num in num_list)
print(result3)  # 输出:1-2-3-4-5
# 方法2:map()函数转换(更高效)
result4 = "|".join(map(str, num_list))
print(result4)  # 输出:1|2|3|4|5

# 4. 实际应用:拼接大量日志内容
log_lines = [
    "2025-08-22 15:00:00 - INFO: 程序启动",
    "2025-08-22 15:00:05 - DEBUG: 连接数据库成功",
    "2025-08-22 15:00:10 - INFO: 处理数据开始"
]
log_content = "\n".join(log_lines)  # 以换行符为分隔符,保留日志格式
print(log_content)
# 输出:
# 2025-08-22 15:00:00 - INFO: 程序启动
# 2025-08-22 15:00:05 - DEBUG: 连接数据库成功
# 2025-08-22 15:00:10 - INFO: 处理数据开始
4.1.4 方式4:使用f-string(Python 3.6+)

f-string(格式化字符串字面值)是Python 3.6引入的新特性,支持在字符串中直接嵌入变量或表达式,语法为 f"字符串内容{变量/表达式}"(前缀 f可大写为 F)。

特点:

  • 优点:

    1. 语法简洁:变量直接嵌入字符串,无需拼接符号,可读性极强;

    2. 支持表达式:可直接在 {}中写入表达式,无需先计算结果再赋值;

    3. 格式灵活:支持数值格式化(保留小数、百分比等)、日期格式化;

    4. 效率高:底层通过编译时解析变量,比传统 %格式化和 str.format()更快;

  • 缺点:仅支持Python 3.6及以上版本,不兼容旧版本。

示例代码:

# 1. 嵌入变量
name = "Alice"
age = 25
result1 = f"My name is {name}, and I am {age} years old."
print(result1)  # 输出:My name is Alice, and I am 25 years old.

# 2. 嵌入表达式(无需先计算)
a = 10
b = 20
result2 = f"a + b = {a + b}, a * b = {a * b}, a^2 = {a ** 2}"
print(result2)  # 输出:a + b = 30, a * b = 200, a^2 = 100

# 3. 嵌入函数调用
def get_full_name(first_name, last_name):
    return f"{first_name} {last_name}"

result3 = f"Full name: {get_full_name('John', 'Doe')}"
print(result3)  # 输出:Full name: John Doe

# 4. 数值格式化(保留小数、百分比、千位分隔符)
pi = 3.1415926
rate = 0.25
salary = 1234567.89
result4 = f"""
数值格式化示例:
- Pi(保留2位小数):{pi:.2f}
- 增长率(百分比):{rate:.0%}
- 薪资(千位分隔符+2位小数):${salary:,.2f}
"""
print(result4)
# 输出:
# 数值格式化示例:
# - Pi(保留2位小数):3.14
# - 增长率(百分比):25%
# - 薪资(千位分隔符+2位小数):$1,234,567.89
# 

# 5. 多行f-string(使用三引号,保留格式)
result5 = f"""
User Profile:
Name: {name}
Age: {age}
Pi Value: {pi:.3f}
Annual Salary: ${salary:,.0f}
"""
print(result5)
# 输出:
# 
# User Profile:
# Name: Alice
# Age: 25
# Pi Value: 3.142
# Annual Salary: $1,234,568
#
4.1.5 方式5:使用str.format()方法

str.format()是Python 2.6引入的格式化拼接方式,语法为 字符串模板.format(参数1, 参数2, ...),通过 {}作为占位符嵌入变量,兼容性好,支持多种传参方式。

特点:

  • 优点:

    1. 兼容性强:支持Python 2.6+和所有Python 3版本,适合需兼容旧环境的项目;

    2. 传参灵活:支持位置参数、关键字参数、字典参数、列表/元组解包;

    3. 格式统一:支持与 f-string类似的数值格式化、对齐等功能;

  • 缺点:语法比 f-string繁琐,效率略低于 f-string

示例代码:

# 1. 位置参数(按顺序传参,占位符用{0}、{1}等标识,可省略索引)
result1 = "My name is {0}, and I am {1} years old.".format("Bob", 30)
print(result1)  # 输出:My name is Bob, and I am 30 years old.
# 省略索引(按顺序匹配)
result1_1 = "My name is {}, and I am {} years old.".format("Bob", 30)
print(result1_1)  # 输出:同上

# 2. 关键字参数(按名称传参,占位符用{name}、{age}等标识,顺序可乱)
result2 = "Name: {name}, Age: {age}, City: {city}".format(age=28, name="Charlie", city="Beijing")
print(result2)  # 输出:Name: Charlie, Age: 28, City: Beijing

# 3. 字典参数(使用**解包字典,占位符与字典键对应)
user_info = {
    "name": "David",
    "age": 35,
    "job": "Engineer"
}
result3 = "Name: {name}, Job: {job}, Age: {age}".format(** user_info)
print(result3)  # 输出:Name: David, Job: Engineer, Age: 35

# 4. 列表/元组参数(使用*解包,按位置匹配)
user_tuple = ("Eve", 22, "Student")
result4 = "Name: {}, Role: {}, Age: {}".format(* user_tuple)
print(result4)  # 输出:Name: Eve, Role: 22, Age: Student(注意:元组元素顺序需与占位符对应)

# 5. 数值格式化(保留小数、整数补0、对齐等)
price = 99.9
count = 5
total = price * count
result5 = "Price: {:.2f}, Count: {:02d}, Total: {:.1f}".format(price, count, total)
# 解释:
# {:.2f} → 浮点数保留2位小数
# {:02d} → 整数占2位,不足补0(d表示整数)
# {:.1f} → 浮点数保留1位小数
print(result5)  # 输出:Price: 99.90, Count: 05, Total: 499.5

# 6. 字符串对齐与填充(与2.4节对齐方法类似)
result6 = "Product: {:<10} | Price: {:>8.2f}".format("Laptop", 5999.99)
# 解释:
# {:<10} → 左对齐,占10位
# {:>8.2f} → 右对齐,占8位,保留2位小数
print(result6)  # 输出:Product: Laptop     | Price:  5999.99

4.2 5种拼接方式的对比与选择建议

为帮助读者在实际开发中快速选择合适的拼接方式,以下是5种方式的详细对比:

拼接方式

适用场景

优点

缺点

效率

Python版本支持

+运算符

少量字符串拼接(2-3个)

语法简单,易于理解

大量拼接时效率极低,产生临时对象

低(大量拼接)、中(少量拼接)

所有版本

*运算符

重复拼接同一字符串(如生成分隔符)

简洁高效,仅一次操作

仅支持重复拼接,无法处理不同内容

所有版本

join()方法

大量字符串拼接(列表/元组中100+元素)

效率极高,仅创建一个新字符串

需先将非字符串元素转为字符串

极高

所有版本

f-string

Python 3.6+,需嵌入变量/表达式、格式化需求

语法简洁、可读性强、支持表达式和格式化、效率高

不兼容Python <3.6

3.6+

str.format()

需兼容旧版本(Python 2.6+)、复杂传参(字典/元组解包)

兼容性好、传参灵活、支持格式化

语法繁琐、效率略低于 f-string

2.6+

选择建议:
  1. 优先选择 f-string:若使用Python 3.6及以上版本,且需嵌入变量、表达式或格式化(如保留小数、日期格式),f-string是最佳选择,兼顾简洁性与效率;

  2. 大量字符串用 join():若需拼接列表、元组中的大量字符串(如1000+元素),join()效率远超 +,是唯一推荐的方式;

  3. 重复拼接用 *:若需生成重复的分隔符(如 "-"*50)或填充符,*最简洁高效;

  4. 兼容旧版本用 str.format():若项目需兼容Python 2.x或Python 3.5及以下版本,str.format()是唯一可靠的格式化方式;

  5. 少量拼接用 +f-string:若仅拼接2-3个字符串,+f-string均可,但 f-string可读性更好(如 f"{a} {b}"a + " " + b更简洁)。

4.3 字符串格式化的高级技巧

除了基础的变量嵌入,字符串格式化还支持更精细的控制,如数值格式、日期格式、对齐方式等,以下重点介绍常用的高级技巧,适用于 f-stringstr.format()

4.3.1 数值格式化(保留小数、百分比、科学计数法)

通过格式化符号可控制数值的显示格式,解决"数值展示不统一"的问题,常用符号如下:

格式化符号

功能描述

示例(f-string

结果

.nf

保留 n位小数(四舍五入)

f"{3.14159:.2f}"

"3.14"

%

转为百分比格式,保留 n位小数

f"{0.253:.1%}"

"25.3%"

e/E

科学计数法,保留 n位小数

f"{1234.5678:.2e}"

"1.23e+03"

d

整数格式(无小数,自动舍弃小数部分)

f"{123.456:d}"

"123"

0nd

整数占 n位,不足部分左侧补0

f"{5:03d}"

"005"

,

千位分隔符(用于大数值,提升可读性)

f"{1234567:,}"

"1,234,567"

+

显示数值正负号(正数带 +,负数带 -

f"{10:+d}, { -10:+d}"

"+10, -10"

示例代码:

# 1. 保留小数(四舍五入)
pi = 3.1415926
print(f"Pi(2位小数): {pi:.2f}")  # 输出:Pi(2位小数): 3.14
print(f"Pi(4位小数): {pi:.4f}")  # 输出:Pi(4位小数): 3.1416

# 2. 百分比格式
rate1 = 0.1234
rate2 = 0.5
print(f"增长率1: {rate1:.1%}")  # 输出:增长率1: 12.3%
print(f"增长率2: {rate2:.0%}")  # 输出:增长率2: 50%

# 3. 科学计数法
large_num = 123456.789
small_num = 0.000123
print(f"大数(科学计数法): {large_num:.2e}")  # 输出:大数(科学计数法): 1.23e+05
print(f"小数(科学计数法): {small_num:.1E}")  # 输出:小数(科学计数法): 1.2E-04

# 4. 整数补0和千位分隔符
count = 8
salary = 1234567.89
print(f"数量(3位补0): {count:03d}")    # 输出:数量(3位补0): 008
print(f"薪资(千位分隔符): ${salary:,.2f}")  # 输出:薪资(千位分隔符): $1,234,567.89

# 5. 显示正负号
profit = 5000
loss = -2000
print(f"利润: {profit:+,.0f}")  # 输出:利润: +5,000
print(f"亏损: {loss:+,.0f}")    # 输出:亏损: -2,000
4.3.2 字符串对齐与填充

在格式化时,可通过 :<(左对齐)、:>(右对齐)、:^(居中对齐)控制字符串的对齐方式,并指定填充字符(默认空格),常用于表格展示、日志排版。

常用对齐格式化符号:

格式化符号

功能描述

示例(f-string

结果

:n<fill

左对齐,总长度 n,不足部分用 fill填充(默认空格)

f"Python:<10-"

"Python----"

:n>fill

右对齐,总长度 n,不足部分用 fill填充(默认空格)

f"Python:>10*"

"****Python"

:n^fill

居中对齐,总长度 n,不足部分用 fill填充(默认空格)

f"Python:^10="

"==Python=="

:n

不指定对齐方式,默认左对齐(字符串)、右对齐(数值)

f"{123:5}"

" 123"(数值右对齐)

示例代码:

# 1. 字符串对齐(指定填充字符)
s = "Python"
print(f"左对齐(10位,-填充): {s:<10-}")  # 输出:左对齐(10位,-填充): Python----
print(f"右对齐(10位,*填充): {s:>10*}")  # 输出:右对齐(10位,*填充): ****Python
print(f"居中对齐(10位,=填充): {s:^10=}")  # 输出:居中对齐(10位,=填充): ==Python==

# 2. 数值与字符串混合对齐(表格展示)
print(f"{'商品名称':<10} {'单价':>8} {'数量':>6} {'总价':>10}")
print("-" * 34)
print(f"{'笔记本电脑':<10} {5999.99:>8.2f} {2:>6} {5999.99 * 2:>10.2f}")
print(f"{'无线鼠标':<10} {99.5:>8.2f} {5:>6} {99.5 * 5:>10.2f}")
# 输出:
# 商品名称        单价    数量        总价
# ----------------------------------
# 笔记本电脑    5999.99      2    11999.98
# 无线鼠标       99.50      5      497.50

# 3. 填充字符为空格(默认)
print(f"{'Name':<10} {'Age':>5}")
print(f"{'Alice':<10} {25:>5}")
# 输出:
# Name        Age  
# Alice        25
4.3.3 日期时间格式化

通过 datetime模块结合格式化字符串,可将日期时间对象按指定格式转换为字符串,满足日志时间戳、报表日期等场景的格式需求。常用的日期时间格式化符号如下:

格式化符号

功能描述

示例

%B

完整月份名称(英文)

August

%b

缩写月份名称(英文)

Aug

%A

完整星期名称(英文)

Friday

%a

缩写星期名称(英文)

Fri

%I

12小时制小时(01-12)

03(对应24小时制15点)

%p

上午/下午标识(AM/PM)

PM

%f

微秒(000000-999999)

123456

Python中需结合 datetime模块的 strftime()方法(字符串格式化时间)实现日期时间格式化,也可在 f-string中直接使用格式化符号(Python 3.6+ 支持),两种方式的核心是一致的。

示例代码1:基础日期时间格式化

from datetime import datetime

# 获取当前日期时间对象
now = datetime.now()  # 格式示例:2025-08-22 15:30:45.123456
print("原始日期时间对象:", now)

# 1. 格式化日期(YYYY-MM-DD)
date_format1 = now.strftime("%Y-%m-%d")
print("日期格式(YYYY-MM-DD):", date_format1)  # 输出:2025-08-22

# 2. 格式化时间(HH:MM:SS)
time_format1 = now.strftime("%H:%M:%S")
print("时间格式(HH:MM:SS):", time_format1)  # 输出:15:30:45

# 3. 完整日期时间(YYYY-MM-DD HH:MM:SS)
full_format1 = now.strftime("%Y-%m-%d %H:%M:%S")
print("完整格式(YYYY-MM-DD HH:MM:SS):", full_format1)  # 输出:2025-08-22 15:30:45

# 4. 带微秒的格式(用于高精度时间戳)
micro_format = now.strftime("%Y-%m-%d %H:%M:%S.%f")
print("带微秒格式:", micro_format)  # 输出:2025-08-22 15:30:45.123456

示例代码2:带星期和月份名称的格式

from datetime import datetime

now = datetime.now()

# 1. 中文风格日期(年-月-日 星期)
# 注意:Python默认不支持中文星期/月份,需手动映射(或使用第三方库如arrow)
weekday_map = {0: "周日", 1: "周一", 2: "周二", 3: "周三", 4: "周四", 5: "周五", 6: "周六"}
chinese_format = f"{now:%Y年%m月%d日} {weekday_map[now.weekday()]}"
print("中文日期格式:", chinese_format)  # 输出:2025年08月22日 周五(需根据实际星期调整)

# 2. 英文风格日期(月份名称+星期)
english_format1 = now.strftime("%B %d, %Y %A")
print("英文日期格式1:", english_format1)  # 输出:August 22, 2025 Friday

# 3. 缩写月份+12小时制时间
english_format2 = now.strftime("%b %d, %Y %I:%M %p")
print("英文日期格式2:", english_format2)  # 输出:Aug 22, 2025 03:30 PM

示例代码3:f-string直接格式化日期(Python 3.6+)

f-string支持在占位符中直接使用 %格式化符号,语法为 f"{datetime对象:%格式化符号}",比 strftime()更简洁。

from datetime import datetime

now = datetime.now()

# 1. 基础格式(YYYY-MM-DD HH:MM:SS)
print(f"当前时间1:{now:%Y-%m-%d %H:%M:%S}")  # 输出:当前时间1:2025-08-22 15:30:45

# 2. 带星期和月份缩写
print(f"当前时间2:{now:%a, %b %d %Y %H:%M}")  # 输出:当前时间2:Fri, Aug 22 2025 15:30

# 3. 日志时间戳格式(常用于日志输出)
print(f"[INFO] {now:%Y-%m-%d %H:%M:%S} - 程序启动成功")
# 输出:[INFO] 2025-08-22 15:30:45 - 程序启动成功

示例代码4:指定日期的格式化(非当前时间)

若需格式化指定日期(如数据库中存储的日期字符串),需先通过 datetime.strptime()解析为 datetime对象,再进行格式化。

from datetime import datetime

# 1. 解析字符串为datetime对象(需指定原始格式)
date_str = "2025-01-01 10:00:00"
date_obj = datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S")  # 解析格式需与字符串匹配
print("解析后的日期对象:", date_obj)  # 输出:2025-01-01 10:00:00

# 2. 格式化为新的字符串(如MM/DD/YYYY格式,美式日期)
new_format = date_obj.strftime("%m/%d/%Y")
print("美式日期格式:", new_format)  # 输出:01/01/2025

# 3. 格式化为带星期的中文格式
weekday_map = {0: "周日", 1: "周一", 2: "周二", 3: "周三", 4: "周四", 5: "周五", 6: "周六"}
chinese_new_format = f"{date_obj:%Y年%m月%d日} {weekday_map[date_obj.weekday()]}"
print("指定日期中文格式:", chinese_new_format)  # 输出:2025年01月01日 周三(需根据实际星期调整)

五、Python字符串高级操作:替换、分割与正则

当基础操作无法满足复杂文本处理需求(如批量替换特殊字符、提取邮箱/手机号、按多规则分割)时,需借助字符串的高级方法与正则表达式。本节将系统讲解字符串替换、分割的进阶用法,并结合 re模块实现复杂文本处理。

5.1 字符串替换的进阶方法

除了基础的 replace(),Python还提供 translate()用于批量替换单个字符,两种方法各有侧重,需根据场景选择。

5.1.1 replace()方法的进阶用法

replace()基础语法为 str.replace(old, new, count=-1),其中 count为可选参数,指定替换次数(默认 -1表示替换所有匹配)。进阶场景包括:

  • 替换为空字符串(实现"删除"效果);

  • 多轮替换(解决单次替换无法覆盖的场景);

  • 限制替换次数(仅替换前N个匹配)。

示例1:替换为空字符串(删除指定子串)
# 1. 删除字符串中的所有空格
s1 = "  Hello  Python  World  "
result1 = s1.replace(" ", "")
print(result1)  # 输出:HelloPythonWorld

# 2. 删除文本中的特殊符号(如逗号、句号)
s2 = "Hello, Python! This is a test."
result2 = s2.replace(",", "").replace("!", "").replace(".", "")
print(result2)  # 输出:Hello Python This is a test

# 3. 删除HTML标签(简化版,复杂场景需用正则)
html_str = "<p>Python is <b>powerful</b>.</p>"
# 先删除<p>和</p>,再删除<b>和</b>
clean_str = html_str.replace("<p>", "").replace("</p>", "").replace("<b>", "").replace("</b>", "")
print(clean_str)  # 输出:Python is powerful.
示例2:限制替换次数(count参数)
# 1. 仅替换前2个"Python"为"Java"
s = "Python is fun. Python is easy. Python is powerful."
result = s.replace("Python", "Java", 2)
print(result)
# 输出:Java is fun. Java is easy. Python is powerful.

# 2. 仅删除前3个空格
s2 = "a b c d e f"
result2 = s2.replace(" ", "", 3)
print(result2)  # 输出:abc d e f
5.1.2 translate()方法:批量替换单个字符

translate()用于批量映射替换单个字符,需先通过 str.maketrans()创建字符映射表(字典或字符对),语法为 str.translate(table)。其核心优势是:一次操作完成多个单个字符的替换,效率高于多次 replace()

语法细节:
  • str.maketrans(x)

    • x为字典,键为待替换的字符(长度1),值为替换后的字符(长度1或None,None表示删除该字符);

    • x为两个长度相同的字符串,第一个字符串的每个字符对应第二个字符串的每个字符(一一映射);

    • x为三个字符串,前两个字符串一一映射,第三个字符串的字符会被删除。

示例1:字典映射替换
# 1. 创建字典:a→@,b→#,c→$
trans_table1 = str.maketrans({"a": "@", "b": "#", "c": "$"})
s1 = "abcabc"
result1 = s1.translate(trans_table1)
print(result1)  # 输出:@#$@#$

# 2. 替换元音字母(a→A,e→E,i→I,o→O,u→U)
vowel_table = str.maketrans({"a": "A", "e": "E", "i": "I", "o": "O", "u": "U"})
s2 = "hello python"
result2 = s2.translate(vowel_table)
print(result2)  # 输出:hEllO pythOn
示例2:字符对映射替换
# 1. 两个字符串一一映射:"abc"→"123"(a→1,b→2,c→3)
trans_table2 = str.maketrans("abc", "123")
s3 = "abc123"
result3 = s3.translate(trans_table2)
print(result3)  # 输出:123123

# 2. 替换数字为中文(0→零,1→一,…,9→九)
num_chinese = "零一二三四五六七八九"
num_table = str.maketrans("0123456789", num_chinese)
s4 = "2025年08月22日"
result4 = s4.translate(num_table)
print(result4)  # 输出:二零二五年零八月二二日
示例3:删除指定字符(第三个参数)
# 1. 创建表:前两个参数为空(无映射),第三个参数为待删除的字符
delete_table1 = str.maketrans("", "", "!., ")
s5 = "Hello, World! This is a test."
result5 = s5.translate(delete_table1)
print(result5)  # 输出:HelloWorldThisisatest

# 2. 删除所有非字母字符
delete_table2 = str.maketrans("", "", "0123456789!@#$%^&*()_+-=[]{}|;':\",./<>? ")
s6 = "Python123! Is fun?"
result6 = s6.translate(delete_table2)
print(result6)  # 输出:PythonIsfun
5.1.3 replace()translate()的对比

方法

适用场景

优点

缺点

示例

replace()

替换子串(长度≥1)、多轮替换

支持子串替换,语法简单

批量单个字符替换效率低

s.replace("Python", "Java")

translate()

批量单个字符替换、删除单个字符

一次操作完成多字符替换,效率高

不支持子串替换(仅单个字符)

s.translate(str.maketrans("abc", "123"))

5.2 字符串分割的进阶方法

基础分割方法 split()仅支持单一分隔符,进阶场景需用到 rsplit()(从右向左分割)、splitlines()(按换行符分割),以及结合正则的 re.split()(按多分隔符分割)。

5.2.1 rsplit():从右向左分割

rsplit()split()语法一致(str.rsplit(sep=None, maxsplit=-1)),但分割方向相反——从字符串末尾开始分割,适用于"从右侧提取最后N部分"的场景(如提取文件路径中的文件名、URL中的参数)。

示例1:提取文件路径中的文件名
# 1. Windows路径(分隔符为\,需转义或用原始字符串)
win_path = r"C:\Users\Admin\Documents\report.pdf"
# 按\从右分割1次,取最后一部分(文件名)
filename1 = win_path.rsplit("\\", 1)[-1]
print(filename1)  # 输出:report.pdf

# 2. Linux/Mac路径(分隔符为/)
linux_path = "/home/admin/documents/data.tar.gz"
# 按/从右分割1次,取最后一部分(带扩展名的文件名)
filename2 = linux_path.rsplit("/", 1)[-1]
print(filename2)  # 输出:data.tar.gz

# 3. 提取文件名(不含扩展名)
# 先按/分割取文件名,再按.从右分割1次取前缀
filename_without_ext = linux_path.rsplit("/", 1)[-1].rsplit(".", 1)[0]
print(filename_without_ext)  # 输出:data.tar
示例2:限制分割次数(maxsplit)
# 1. 从右分割2次,获取前两部分
s = "a-b-c-d-e"
result1 = s.rsplit("-", 2)
print(result1)  # 输出:['a-b-c', 'd', 'e'](从右分割2次,分成3部分)

# 2. 对比split()与rsplit()(maxsplit=1)
result2 = s.split("-", 1)    # 从左分割1次
result3 = s.rsplit("-", 1)   # 从右分割1次
print("split()结果:", result2)  # 输出:split()结果:['a', 'b-c-d-e']
print("rsplit()结果:", result3) # 输出:rsplit()结果:['a-b-c-d', 'e']
5.2.2 splitlines():按换行符分割

splitlines()专门用于按换行符分割字符串,返回包含各行内容的列表,语法为 str.splitlines(keepends=False),其中 keepends为可选参数,若为 True则保留换行符。

相较于 split("\n")splitlines()的优势是:支持所有换行符类型(\n\r\r\n等),且能自动处理不同操作系统的换行格式(Windows:\r\n,Linux:\n,Mac:\r)。

示例1:基础用法(保留/不保留换行符)
# 1. 混合换行符的字符串(\n、\r\n)
s1 = "Line1\nLine2\r\nLine3\rLine4"
# 不保留换行符(默认)
result1 = s1.splitlines()
print(result1)  # 输出:['Line1', 'Line2', 'Line3', 'Line4']

# 保留换行符(keepends=True)
result2 = s1.splitlines(keepends=True)
print(result2)  # 输出:['Line1\n', 'Line2\r\n', 'Line3\r', 'Line4']
示例2:处理多行文本(如日志、配置文件)
# 多行日志文本
log_text = """2025-08-22 15:00:00 - INFO: 程序启动
2025-08-22 15:00:05 - DEBUG: 连接数据库成功
2025-08-22 15:00:10 - ERROR: 数据读取失败
2025-08-22 15:00:15 - INFO: 程序退出"""

# 按换行符分割为每行列表
log_lines = log_text.splitlines()
# 逐行提取日志级别(如INFO、DEBUG)
for line in log_lines:
    # 按" - "分割,取第二部分(如"INFO: 程序启动"),再按": "分割取级别
    level = line.split(" - ")[1].split(": ")[0]
    print(f"日志级别:{level:6} | 日志内容:{line}")

# 输出:
# 日志级别:INFO   | 日志内容:2025-08-22 15:00:00 - INFO: 程序启动
# 日志级别:DEBUG  | 日志内容:2025-08-22 15:00:05 - DEBUG: 连接数据库成功
# 日志级别:ERROR  | 日志内容:2025-08-22 15:00:10 - ERROR: 数据读取失败
# 日志级别:INFO   | 日志内容:2025-08-22 15:00:15 - INFO: 程序退出
5.2.3 re.split():按多分隔符分割

当需要按多个不同分隔符(如 ,;|、空格)分割字符串时,基础 split()无法实现,需借助 re模块的 re.split()函数,语法为 re.split(pattern, string, maxsplit=0, flags=0)

  • pattern:正则表达式模式(如 r"[,;|]"表示按 ,;|分割);

  • maxsplit:最大分割次数(默认0表示分割所有);

  • flags:正则匹配标志(如 re.IGNORECASE表示忽略大小写)。

示例1:按多字符分隔符分割
import re

# 1. 按,、;、|分割字符串
s1 = "Apple,Banana;Orange|Mango-Grape"
# 正则模式:匹配,、;、|、-中的任意一个
pattern1 = r"[,;|-]"
result1 = re.split(pattern1, s1)
print(result1)  # 输出:['Apple', 'Banana', 'Orange', 'Mango', 'Grape']

# 2. 按空白字符或逗号分割(支持多个连续空格)
s2 = "Hello,   Python is fun;   I love it"
pattern2 = r"[,;]\s*|\s+"  # 匹配",+空格"、";+空格"或"多个空格"
result2 = re.split(pattern2, s2)
print(result2)  # 输出:['Hello', 'Python', 'is', 'fun', 'I', 'love', 'it']
示例2:保留分割符(用括号分组)

若需在分割后保留分隔符,可将正则模式中的分隔符用括号 ()分组,此时分割结果会包含分隔符。

import re

s = "a-b+c*d/e"
# 正则模式:用括号分组保留分隔符(-、+、*、/)
pattern = r"(-|\+|\*|/)"  # +需转义为\+
result = re.split(pattern, s)
print(result)  # 输出:['a', '-', 'b', '+', 'c', '*', 'd', '/', 'e']

# 重构字符串(恢复原格式,验证分割正确性)
reconstructed = "".join(result)
print(reconstructed)  # 输出:a-b+c*d/e(与原字符串一致)

5.3 正则表达式与复杂文本处理

正则表达式(Regular Expression)是处理复杂文本的"瑞士军刀",能实现模糊匹配、精准提取、批量替换等功能。Python通过 re模块提供正则支持,以下重点讲解 re模块的核心函数及典型应用场景。

5.3.1 re模块核心函数速览

函数

语法

功能描述

关键特点

re.match()

re.match(pattern, string, flags=0)

从字符串开头匹配模式,成功返回 Match对象,失败返回 None

仅匹配开头,不匹配则返回None

re.search()

re.search(pattern, string, flags=0)

在整个字符串中搜索第一个匹配,成功返回 Match对象,失败返回 None

搜索整个字符串,仅返回第一个匹配

re.findall()

re.findall(pattern, string, flags=0)

搜索整个字符串,返回所有匹配子串的列表(无匹配则返回空列表)

无需循环,直接获取所有结果

re.sub()

re.sub(pattern, repl, string, count=0, flags=0)

替换所有匹配子串为 repl(字符串或函数),count指定替换次数

支持复杂替换逻辑(如函数动态生成替换值)

re.compile()

re.compile(pattern, flags=0)

编译正则模式为 Pattern对象,可重复使用

多次使用同一模式时,提升效率(避免重复解析)

5.3.2 典型应用场景:提取敏感信息(邮箱、手机号)
场景1:提取文本中的所有手机号

中国手机号格式规则:11位数字,以13/14/15/17/18/19开头,正则模式为 r"1[345789]\d{9}"

import re

# 原始文本(含手机号、固定电话)
text = """联系电话:13812345678(工作),备用电话:19987654321,
家庭固定电话:010-12345678,朋友电话:15811112222"""

# 正则模式:匹配11位手机号(开头为13/14/15/17/18/19)
phone_pattern = r"1[345789]\d{9}"

# 1. 提取所有手机号(re.findall())
phones = re.findall(phone_pattern, text)
print("提取的手机号:", phones)  # 输出:提取的手机号:['13812345678', '19987654321', '15811112222']

# 2. 验证手机号格式(re.match())
def is_valid_phone(phone):
    # 用^和$确保全字符串匹配(避免匹配12位数字中的前11位)
    return bool(re.match(r"^1[345789]\d{9}$", phone))

test_phones = ["13812345678", "12345678901", "138123456789"]
for phone in test_phones:
    print(f"手机号{phone}:{'有效' if is_valid_phone(phone) else '无效'}")
# 输出:
# 手机号13812345678:有效
# 手机号12345678901:无效(开头为12,不符合规则)
# 手机号138123456789:无效(12位数字)
场景2:提取文本中的所有邮箱

邮箱格式规则:用户名@域名.后缀,其中用户名可包含字母、数字、下划线、连字符,域名可包含字母、数字、连字符,后缀为2-6位字母(如 comorgcn),正则模式为 r"[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+\.[a-zA-Z]{2,6}"

import re

# 原始文本(含多个邮箱)
text = """我的个人邮箱是alice123@qq.com,工作邮箱是bob_smith@company.org,
备用邮箱是charlie-456@gmail.com,无效邮箱是david@.com、eve@123"""

# 正则模式:匹配邮箱
email_pattern = r"[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+\.[a-zA-Z]{2,6}"

# 1. 提取所有有效邮箱
emails = re.findall(email_pattern, text)
print("提取的有效邮箱:", emails)
# 输出:提取的有效邮箱:['alice123@qq.com', 'bob_smith@company.org', 'charlie-456@gmail.com']

# 2. 替换邮箱为脱敏格式(隐藏@前的部分字符)
def mask_email(email):
    # 用re.sub()替换@前的字符(保留前3位,其余用*代替)
    return re.sub(r"([a-zA-Z0-9_-]{3})[a-zA-Z0-9_-]*@", r"\1****@", email)

# 对每个邮箱进行脱敏
masked_emails = [mask_email(email) for email in emails]
print("脱敏后的邮箱:", masked_emails)
# 输出:脱敏后的邮箱:['ali****@qq.com', 'bob****@company.org', 'cha****@gmail.com']
5.3.3 典型应用场景:批量替换与文本清洗
场景1:去除文本中的所有HTML标签

HTML标签格式为 <标签名></标签名>,正则模式为 r"<[^>]+>"(匹配 <开头、>结尾,中间不含 >的内容)。

import re

# 含HTML标签的文本
html_text = """
<div class="article">
    <h1>Python字符串操作</h1>
    <p>本文讲解<span style="color:red">Python字符串</span>的核心用法。</p>
    <a href="https://python.org">Python官网</a>
</div>
"""

# 正则模式:匹配所有HTML标签
html_pattern = r"<[^>]+>"

# 1. 去除所有HTML标签
clean_text = re.sub(html_pattern, "", html_text).strip()
print("清洗后的文本:")
print(clean_text)
# 输出:
# Python字符串操作
# 
# 本文讲解Python字符串的核心用法。
# 
# Python官网
场景2:统一文本中的日期格式

将文本中的 MM/DD/YYYY格式(美式日期)统一改为 YYYY-MM-DD格式(ISO日期),需先匹配美式日期,再通过分组重构格式。

import re

# 含混合日期格式的文本
text = """会议时间:08/22/2025(美式),截止日期:2025-09-30(ISO),
历史记录:01/01/2024,下次更新:12/31/2025"""

# 正则模式:匹配MM/DD/YYYY格式(分组提取月、日、年)
date_pattern = r"(\d{2})/(\d{2})/(\d{4})"

# 替换为YYYY-MM-DD格式(用\1表示第一个分组(月),\2表示日,\3表示年)
unified_text = re.sub(date_pattern, r"\3-\1-\2", text)
print("统一日期格式后的文本:")
print(unified_text)
# 输出:
# 会议时间:2025-08-22(美式),截止日期:2025-09-30(ISO),
# 历史记录:2024-01-01,下次更新:2025-12-31

六、字符串操作性能优化与常见问题

在处理大量文本数据(如日志分析、数据清洗)时,字符串操作的性能至关重要;同时,新手在使用过程中也容易遇到索引越界、类型错误等问题。本节将总结性能优化技巧与常见问题解决方案,帮助读者写出高效、健壮的代码。

6.1 字符串操作性能优化技巧

6.1.1 避免频繁使用+拼接大量字符串

字符串不可变性导致每次 +拼接都会创建新字符串,当拼接10万级以上字符串时,效率极低。优化方案:使用 join()方法,先将字符串存入列表,再一次性拼接。

示例对比:
import time

# 测试数据:10万个字符串
n = 100000
str_list = [str(i) for i in range(n)]

# 方案1:使用+拼接(效率低)
start_time = time.time()
result = ""
for s in str_list:
    result += s
end_time = time.time()
print(f"+拼接耗时:{end_time - start_time:.4f}秒")  # 输出:约0.1-0.3秒(视环境而定)

# 方案2:使用join()拼接(效率高)
start_time = time.time()
result = "".join(str_list)
end_time = time.time()
print(f"join()拼接耗时:{end_time - start_time:.4f}秒")  # 输出:约0.001-0.005秒
6.1.2 优先使用f-string而非str.format()

f-string是Python 3.6+的优化特性,底层通过编译时解析变量,避免 str.format()的运行时参数解析开销,效率更高。

示例对比:
import time

# 测试数据:10万次格式化
n = 100000
name = "Alice"
age = 25

# 方案1:str.format()
start_time = time.time()
for _ in range(n):
    result = "Name: {}, Age: {}".format(name, age)
end_time = time.time()
print(f"str.format()耗时:{end_time - start_time:.4f}秒")  # 输出:约0.02-0.05秒

# 方案2:f-string
start_time = time.time()
for _ in range(n):
    result = f"Name: {name}, Age: {age}"
end_time = time.time()
print(f"f-string耗时:{end_time - start_time:.4f}秒")  # 输出:约0.005-0.01秒
6.1.3 编译正则表达式(re.compile()

若需多次使用同一正则模式(如循环中匹配),应先编译模式为 Pattern对象,避免每次匹配时重复解析正则表达式,提升效率。

示例对比:
import re
import time

# 测试数据:10万次匹配
n = 100000
text = "Phone: 13812345678, Email: alice@qq.com"
phone_pattern = r"1[345789]\d{9}"

# 方案1:不编译,每次调用re.findall()
start_time = time.time()
for _ in range(n):
    re.findall(phone_pattern, text)
end_time = time.time()
print(f"未编译正则耗时:{end_time - start_time:.4f}秒")  # 输出:约0.1-0.2秒

# 方案2:先编译,再重复使用
compiled_pattern = re.compile(phone_pattern)
start_time = time.time()
for _ in range(n):
    compiled_pattern.findall(text)
end_time = time.time()
print(f"编译正则耗时:{end_time - start_time:.4f}秒")  # 输出:约0.05-0.1秒
6.1.4 用startswith()/endswith()替代切片判断

判断字符串是否以指定前缀/后缀开头时,startswith()/endswith()是Python内置优化方法,效率高于切片判断(如 s[:2] == "Py")。

示例对比:
import time

# 测试数据:10万次判断
n = 100000
s = "Python is fun"

# 方案1:切片判断
start_time = time.time()
for _ in range(n):
    if s[:6] == "Python":
        pass
end_time = time.time()
print(f"切片判断耗时:{end_time - start_time:.4f}秒")  # 输出:约0.008-0.015秒

# 方案2:startswith()判断
start_time = time.time()
for _ in range(n):
    if s.startswith("Python"):
        pass
end_time = time.time()
print(f"startswith()耗时:{end_time - start_time:.4f}秒")  # 输出:约0.002-0.005秒

6.2 字符串操作常见问题与解决方案

6.2.1 问题1:索引越界(IndexError)

问题描述:通过索引访问字符时,索引值超出字符串有效范围(正向索引 > len(s)-1,反向索引 < -len(s)),导致 IndexError: string index out of range

示例:

s = "Python"  # 有效索引:0-5(正向),-1到-6(反向)
print(s[6])   # 报错:IndexError
print(s[-7])  # 报错:IndexError

解决方案:

  1. 操作前检查索引范围:if 0 <= index < len(s): ...

  2. 使用切片替代单个索引(切片越界返回空字符串,不报错);

  3. 获取末尾字符直接用 s[-1](无需计算长度)。

优化代码:

s = "Python"
index = 6

# 方案1:检查索引范围
if 0 <= index < len(s):
    print(s[index])
else:
    print(f"索引{index}超出范围(有效范围:0-{len(s)-1})")

# 方案2:切片替代单个索引
print(s[index:index+1])  # 输出:""(无报错)

# 方案3:安全获取末尾字符
print(s[-1])  # 输出:n
6.2.2 问题2:字符串拼接类型错误(TypeError)

问题描述:使用 +拼接时,其中一个操作数不是字符串(如整数、浮点数),导致 TypeError: can only concatenate str (not "int") to str

示例:

age = 25
print("My age is " + age)  # 报错:TypeError

解决方案:

  1. str()转换非字符串类型;

  2. 使用 f-stringstr.format()(自动处理类型转换)。

优化代码:

age = 25
# 方案1:str()转换
print("My age is " + str(age))  # 输出:My age is 25

# 方案2:f-string(推荐)
print(f"My age is {age}")  # 输出:My age is 25
6.2.3 问题3:strip()无法去除中间空白字符

问题描述:新手误以为 strip()能去除字符串中间的空白字符,实际 strip()仅去除首尾的指定字符(默认空白字符)。

示例:

s = "  Hello  Python  "
print(s.strip())  # 输出:Hello  Python(中间空格未去除)

解决方案:

  1. 去除所有空白字符:用 replace(" ", "")re.sub(r"\s+", "", s)

  2. 合并连续空白字符:用 re.sub(r"\s+", " ", s)

优化代码:

s = "  Hello  Python  "
# 方案1:去除所有空白字符
print(s.replace(" ", ""))  # 输出:HelloPython

# 方案2:合并连续空白字符(保留单个空格)
import re
print(re.sub(r"\s+", " ", s).strip())  # 输出:Hello Python

七、总结与实战建议

7.1 核心知识点梳理

  1. 基础认知:字符串是不可变序列,支持正向/反向索引,所有"修改"操作均通过创建新字符串实现;

  2. 基础操作:查找(find()/count())、判断(isalpha()/startswith())、转换(lower()/title())、对齐(ljust()/center())、修剪(strip()),是文本处理的"基本功";

  3. 核心操作:

    • 切片:str[start:end:step],左闭右开原则,支持正向/反向切片,可实现子串提取、逆序;

    • 拼接与格式化:+(少量)、join()(大量)、f-string(高效格式化)、str.format()(兼容);

  4. 高级操作:替换(replace()/translate())、分割(rsplit()/splitlines())、正则(re.findall()/re.sub()),解决复杂文本处理需求。

7.2 实战建议

  1. 场景优先:根据需求选择合适的方法(如大量拼接用 join(),格式化用 f-string,复杂匹配用正则);

  2. 性能意识:处理大量数据时,避免频繁 +拼接、重复解析正则,优先使用优化方法;

  3. 兼容性考虑:若项目需兼容Python 2.x或3.5及以下版本,用 str.format()替代 f-string

  4. 工具辅助:正则调试可使用在线工具(如 Regex101),提升效率;

  5. 实战练习:通过项目巩固技能(如日志分析工具、文本脱敏脚本、CSV数据清洗)。

Python字符串操作是编程入门的核心,也是后续学习Web开发、数据分析、AI等领域的基础。建议通过大量练习(如LeetCode字符串题目、实际项目开发)加深理解,做到"学以致用"。

Logo

惟楚有才,于斯为盛。欢迎来到长沙!!! 茶颜悦色、臭豆腐、CSDN和你一个都不能少~

更多推荐