☰
Python 如何截取字符函数
2026/10/8 7:45:34 网站建设 项目流程

前言


先纠一个前提:Python 里并没有一个专门叫"截取字符"的内置函数。dir(__builtins__)里找不到substr、substring、mid这类名字,那是 JavaScript、Java、SQL 等语言的习惯。Python 截取子串的主力是切片(slicing),它用的是语法而不是函数调用;在此之上,str提供了一批"按条件定位"的方法,re模块提供了"按模式定位"的能力。


另一个常见误解是把"截取"和"删除"混为一谈。截取只是从原串里取出一段,原串始终不动——str不可变,任何取法都返回新串,不存在"从原串里挖掉一块"的操作。


本文把"截取"按定位方式分层讲:按位置、按分隔符、按起止标记、按模式,每种给出可直接运行的写法,最后用一个解析文件路径的实战串起来。代码基于 Python 3.8 及以上。Python 2.7 已于 2020 年 1 月 1 日停止维护,本文不采用任何 Python 2 专有语法。


一、按位置截取:切片


切片写作s[start:stop:step],遵循左闭右开——含start,不含stop。省略start就从开头,省略stop就到结尾。


# 适用于 Python 3.8+
s = "https://example.com/path/file.txt"
print(s[:5]) # https 前 5 个字符
print(s[-4:]) # .txt 最后 4 个字符
print(s[8:19]) # example.com 从下标 8 到 18
print(s[::2]) # 每隔一个取一个

切片最友好的一点是越界不报错:下标太小会被夹成 0,太大被夹成长度,起点不小于终点就得到空串。真正会报IndexError的是索引(s[i]),不是切片。


# 适用于 Python 3.8+
s = "abc"
print(s[1:100]) # bc 越界被夹到末尾,不报错
print(s[10:20]) # '' 起点已越过末尾,得到空串
# print(s[10]) # IndexError: string index out of range

二、按分隔符截取:split 与 partition


str.split(sep=None, maxsplit=-1)把字符串切成列表;str.partition(sep)在第一个分隔符处切成三元组,并且把分隔符本身也保留在结果里。


# 适用于 Python 3.8+
line = "key=value"
print(line.split("=")) # ['key', 'value']

head, sep, tail = line.partition("=")
print(head, "|", sep, "|", tail) # key | = | value

# partition 找不到分隔符时返回 (原串, '', '')
print("no-equals".partition("=")) # ('no-equals', '', '')

split和partition的关键差别在于:split返回的是去掉分隔符的列表,字段数不定;partition永远返回三个元素,适合"只切一刀"的场景,也不需要先判断分隔符存不存在(不存在时sep为空串,一目了然)。


str.rpartition(sep)则从右边找第一个分隔符,取后缀特别方便:


# 适用于 Python 3.8+
path = "/a/b/c.txt"
print(path.rpartition("/")[2]) # c.txt
print(path.rpartition("/")[0]) # /a/b

三、按起止标记截取:find / index 加切片


要取"两个标记之间"的内容,先用find或index拿到位置,再切片。


# 适用于 Python 3.8+
s = "user@example.com"
at = s.find("@")
print(s[:at]) # user
print(s[at + 1:]) # example.com

find与index的区别只在找不到时:find返回-1,index抛ValueError。




方法找不到时适合



s.find(sub)返回-1想自己判断存在性

s.index(sub)抛ValueError认为找不到就是错误

s.rfind(sub)返回-1从右往左找

s.rindex(sub)抛ValueError从右往左找且必须存在



要取两个不同标记之间的内容,需要分别定位起点和终点:


# 适用于 Python 3.8+
s = "结果是 [成功] 请查收"
left = s.find("[")
right = s.find("]")
if left != -1 and right != -1 and right > left:
print(s[left + 1:right]) # 成功

left + 1是为了跳过开头的[,right作为切片的终点天然不含],所以右边界不用减一。


四、按模式截取:re.search 与 re.findall


内容长度不固定、位置也不固定时,用正则定义"长什么样",再取匹配到的片段。


# 适用于 Python 3.8+
import re

text = "日期是 2024-05-06 发布"
m = re.search(r"\d{4}-\d{2}-\d{2}", text)
if m:
print(m.group()) # 2024-05-06
print(m.start(), m.end()) # 4 14

# 一次取出所有匹配
print(re.findall(r"[a-z]+", "ab12cd34ef")) # ['ab', 'cd', 'ef']

re.search从任意位置找第一个匹配,返回Match对象或None;re.match只从开头匹配;re.findall返回所有匹配组成的列表。拿不准该用哪个时记住:找全文里的第一处用search,找开头的用match,找全部用findall。


用命名分组能让"取哪一段"更清楚:


# 适用于 Python 3.8+
import re

m = re.search(r"(?P<year>\d{4})-(?P<month>\d{2})", "2024-05")
if m:
print(m.group("year")) # 2024
print(m.group("month")) # 05

实战:从一行日志里截出各个字段


下面把上面的方法合起来用:一段形如[2024-05-06 10:00:00] ERROR user=alice msg=failed的日志,逐段截出时间、级别、用户和消息。


# 适用于 Python 3.8+
import re

LINE = "[2024-05-06 10:00:00] ERROR user=alice msg=failed"

def parse(line):
result = {}

# 1) 方括号里的时间:用 find + 切片
l = line.find("[")
r = line.find("]")
if l != -1 and r != -1:
result["time"] = line[l + 1:r]
rest = line[r + 1:].strip()
else:
rest = line

# 2) 级别是第一个空白分隔的词
level, _, rest = rest.partition(" ")
result["level"] = level

# 3) 后面的 key=value 用 split 逐段截取
for chunk in rest.split():
key, sep, value = chunk.partition("=")
if sep:
result[key] = value

return result

print(parse(LINE))
# {'time': '2024-05-06 10:00:00', 'level': 'ERROR',
# 'user': 'alice', 'msg': 'failed'}

这里刻意混用了三种定位方式:方括号边界固定但内容不定,用find加切片;级别是"第一个词",用partition;剩下的键值对个数不固定,用split()迭代。方法选对了,代码就不需要写"如果找不到就……"的一大堆分支。


常见坑点



  1. find返回 -1 时直接切片


❌s[s.find("@") + 1:],若没有@,-1 + 1是 0,会把整串当结果返回,静默出错


✅ 先判断if (i := s.find("@")) != -1:再切片,或用partition拿sep判空



  1. 把切片和索引的容错性记反


❌ 以为s[100:200]会抛IndexError


✅ 切片越界返回空串或夹到边界;抛IndexError的是s[100]



  1. partition的第二个元素没接住


❌head, tail = s.partition("="),会抛ValueError: too many values to unpack


✅ 三元组要接三个:head, sep, tail = s.partition("="),并检查sep非空



  1. 右边界忘了"不含"


❌s[left:right]想包含right位置那个字符


✅ 切片不含终点,要包含就写s[left:right + 1]



  1. 中文按字节数取


❌ 以为len("中文")是 6,按此切片切出半个字符


✅len按字符算,"中文"长度是 2;要按字节处理先encode



  1. 把re.match当re.search用


❌re.match(r"\d+", "abc123")返回None,因为match只匹配开头


✅ 只想在开头匹配用match,全文找第一处用search



  1. 靠split("")拆分


❌"abc".split(""),抛ValueError: empty separator


✅ 想逐字符遍历直接for ch in s,或list(s)



  1. 沿用 Python 2 的截取写法


❌ 用string.split(s, ",")的函数式旧调用,或用u"..."当必需前缀


✅ Python 3 里用方法式s.split(","),字面量默认就是 Unicode;Python 2.7 已于 2020 年 1 月 1 日 EOL


总结




想怎么截用什么



按固定位置切片s[a:b]

取全部片段s.split(sep)

只切一刀、保留分隔符s.partition(sep)/s.rpartition(sep)

取某标记前 / 后find定位 + 切片

按内容模式re.search/re.findall



"截取"在 Python 里从来不是一个函数,而是一套先定位、再切片的组合动作。定位方式决定了选哪个工具:位置已知就用切片,靠分隔符就用split系,靠前后标记就用find加切片,靠内容特征就上正则。把这四种分清楚,绝大多数"取字符串中间那一块"的需求都能一步到位,也就不会再去找那个并不存在的"截取函数"了。





需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询