前面一章,我们已经把常见字符串方法整体过了一遍。 你已经知道,字符串不是只能拿来打印,它还可以拆、可以拼、可以替换、可以清洗。
但在真实开发里,还有一类操作出现得特别频繁:
判断一段文本里有没有某个内容 判断它是不是以某个内容开头 判断它是不是以某个内容结尾 找到某个关键词第一次出现的位置
这些动作听起来很普通,但实际用得非常多。
比如:
判断文件是不是 pdf 判断网址是不是以 https 开头 判断邮箱里有没有 @ 判断日志里有没有 error 判断一条消息是不是命令开头 找到某个关键词在文本里的位置
这些需求,本质上都属于同一类:
查找与判断
这一章我们就把字符串里最常用的这几个动作彻底讲清楚。 真正掌握以后,你会发现,很多文本处理题,本质上都绕不开这几个基础操作。
一、为什么查找与判断这么重要
因为程序面对真实文本时,第一步常常不是修改,而是先确认。
先确认有没有 先确认是不是 先确认在什么位置 然后再决定下一步做什么
比如用户上传一个文件,你得先判断后缀。 比如一条日志进来,你得先判断有没有报错关键词。 比如收到一个网址,你得先判断是不是合法链接开头。 比如读到一段文本,你得先找到某个标记在哪里。
所以查找与判断,其实就是文本处理里的第一道门。
你连门都没进,后面的拆分、替换、提取自然也做不顺。
二、先认识最常用的四个工具
这一章的主角主要有四个:
startswith()endswith()find()in
你先不用急着背。 我们先用最直白的话把它们的用途说清楚。
startswith()判断字符串是不是以某个内容开头
endswith()判断字符串是不是以某个内容结尾
find()查找某个内容第一次出现的位置
in判断某个内容在不在字符串里
你会发现,这四个工具里,有的是偏判断,有的是偏定位。 它们经常搭配着用。
三、startswith():判断是不是以某个内容开头
先看最简单的例子:
url = 'https://example.com'print(url.startswith('https://'))
输出:
True
意思很直接:
这个字符串,确实是以 https:// 开头的
再看一个反例:
url = 'http://example.com'print(url.startswith('https://'))
输出:
False
因为它不是以 https:// 开头。
这个方法特别适合做开头规则判断。
比如:
判断网址协议 判断文件名前缀 判断用户输入是不是命令 判断一条文本是不是以某个关键词起头
它最大的优点就是:
语义非常清楚
你一看代码就知道,这里在判断开头,而不是去硬切片比较。
四、为什么 startswith() 往往比切片更自然
比如判断文件名是不是以 data_ 开头。
你当然可以这样写:
filename = 'data_report.txt'print(filename[:5] == 'data_')
这能跑,也没错。
但如果写成:
filename = 'data_report.txt'print(filename.startswith('data_'))
是不是明显更顺眼。
因为后者直接把你的意图说出来了:
我在判断它是不是以 data_ 开头
而不是让别人先看切片,再猜你的意思。
所以一个非常实用的经验是:
凡是判断开头,优先想到 startswith()而不是自己先切片再比
五、startswith() 在真实场景里有多常见
非常常见。
比如判断命令输入:
cmd = '/help'print(cmd.startswith('/'))
如果是 True,说明这可能是一条命令。
比如判断日志级别:
log = 'ERROR: 文件读取失败'print(log.startswith('ERROR'))
比如判断某个文件是否属于某类命名规则:
filename = 'img_001.png'print(filename.startswith('img_'))
这些都特别接近实际开发。
你以后做文件处理、命令行工具、日志分析、爬虫过滤时,经常会看到这种写法。
六、startswith() 还能一次判断多个开头
这点很多新手一开始不知道,但很好用。
比如你想判断一个文件是不是图片文件名,而且前缀可能是 img_ 或 photo_:
filename = 'photo_001.png'print(filename.startswith(('img_', 'photo_')))
输出:
True
注意这里传进去的是一个元组。 意思是:
只要符合其中任意一个开头,就算真
这在做多规则匹配时特别方便。 你不用写一长串 or。
比如判断一个网址是不是 http 或 https:
url = 'http://example.com'print(url.startswith(('http://', 'https://')))
这类写法在实战里很常见。
七、endswith():判断是不是以某个内容结尾
这个和 startswith() 是一对。
看例子:
filename = 'report.pdf'print(filename.endswith('.pdf'))
输出:
True
意思很清楚:
这个文件名,确实是以 .pdf 结尾的
再看:
filename = 'report.txt'print(filename.endswith('.pdf'))
输出:
False
它最常见的用途,就是判断后缀。
比如:
文件扩展名判断 网址后缀判断 路径结尾判断 用户名格式判断 文本标点结尾判断
八、endswith() 为什么在文件处理里特别常见
因为文件类型判断实在太高频了。
比如判断是不是图片:
filename = 'cat.jpg'print(filename.endswith('.jpg'))
判断是不是 Excel 文件:
filename = 'sales.xlsx'print(filename.endswith('.xlsx'))
判断是不是 Python 脚本:
filename = 'main.py'print(filename.endswith('.py'))
你会发现,后缀这件事如果自己切片也能做,但 endswith() 更直接、更稳。
比如你手动切片:
filename[-4:] == '.pdf'
虽然行,但可读性还是不如:
filename.endswith('.pdf')
特别是后缀长度不固定时,后者明显更舒服。
九、endswith() 也支持多个候选结尾
这点和 startswith() 一样。
比如你想判断一个文件是不是图片格式,可能是 .jpg、.png、.gif:
filename = 'avatar.png'print(filename.endswith(('.jpg', '.png', '.gif')))
输出:
True
这在文件筛选、批量处理、目录遍历时特别常见。
比如你后面处理一堆文件时,经常会写这种逻辑:
if filename.endswith(('.jpg', '.png')): print('这是图片文件')
一旦知道这个写法,代码会简洁很多。
十、startswith() 和 endswith() 的本质是什么
它们本质上都是做真假判断。
结果只有两个可能:
TrueFalse
所以它们特别适合放在 if 判断里。
比如:
filename = 'report.pdf'if filename.endswith('.pdf'): print('可以按 PDF 文件处理')else: print('不是 PDF 文件')
再比如:
url = 'https://example.com'if url.startswith('https://'): print('安全链接')
这也是为什么这两个方法特别适合拿来做规则过滤。
因为它们不是告诉你位置,而是直接告诉你:
是不是
十一、find():查找某个内容第一次出现的位置
前面两个方法更偏判断。find() 则更偏定位。
看例子:
text = 'I love Python'print(text.find('Python'))
输出:
7
意思是:
Python 这段内容,第一次从索引 7 开始出现
如果我们把这句话的位置标一下:
I _ l o v e _ P y t h o n0123456789101112
你就会更容易明白为什么返回的是 7。
所以 find() 的核心价值是:
帮你找到某段内容第一次出现的起始位置
十二、find() 找不到时会返回什么
这个点一定要记住。
如果找不到,它不会报错,而是返回:
-1
看例子:
text = 'I love Python'print(text.find('Java'))
输出:
-1
这说明 Java 不在这段文本里。
这个设计非常实用。 因为你可以根据返回值判断下一步怎么做,而不是程序直接崩掉。
比如:
text = 'I love Python'pos = text.find('Python')if pos != -1: print('找到了,位置是', pos)else: print('没找到')
这类写法很常见。
十三、find() 和 in 有什么区别
这也是很多新手容易混淆的点。
先看 in:
text = 'I love Python'print('Python'in text)
输出:
True
它只告诉你:
在不在
再看 find():
print(text.find('Python'))
输出:
7
它告诉你:
在,而且从哪开始
所以区别很简单:
in 更适合做真假判断find() 更适合做位置定位
如果你只想知道有没有,用 in 更直接。 如果你还想知道在哪,用 find() 更合适。
十四、什么时候优先用 in
当你只关心有没有的时候。
比如判断文本里有没有关键词:
text = '欢迎学习 Python'print('Python'in text)
判断邮箱里有没有 @:
email = 'tom@example.com'print('@'in email)
判断日志里有没有 error:
log = '2026-03-26 error: file not found'print('error'in log)
这些需求,本质上都不关心位置,只关心存不存在。 那 in 就非常合适。
它的好处就是简单、直观、好记。
十五、什么时候优先用 find()
当你除了想知道有没有,还想进一步处理位置时。
比如你想找到 @ 在邮箱里的位置:
email = 'tom@example.com'print(email.find('@'))
比如你想从某个标记位置开始切片:
text = 'name=tom'pos = text.find('=')print(pos)print(text[pos + 1:])
输出:
4tom
这里就很典型。
先用 find() 定位 再用切片取后面的内容
这就是字符串处理里非常常见的一套组合拳。
十六、in 的语法为什么特别像自然语言
比如:
'Python'in text
你几乎可以直接把它读成:
Python 在不在 text 里面
这就是它为什么那么受欢迎。
因为不光短,而且语义非常自然。
Python 这门语言有一个很大的特点,就是很多写法读起来就像说人话。in 就是一个很典型的例子。
所以以后你遇到成员判断,不只是字符串,列表、字典、集合里也会大量看到 in。
只是这一章,我们先聚焦在字符串里。
十七、in 在字符串里判断的是什么
它判断的是:
某段子串是否存在于原字符串中
看例子:
text = 'I love Python'print('love'in text)
输出:
True
说明 love 这整段就在里面。
再看:
print('thon'in text)
输出:
True
因为 Python 里本来就包含 thon 这段子串。
再看:
print('Java'in text)
输出:
False
这说明,in 判断的不是单个字符专属,它既能判断字符,也能判断一整段子串。
十八、not in:判断某段内容不在里面
既然有 in,自然也就有 not in。
比如:
text = 'I love Python'print('Java'notin text)
输出:
True
因为 Java 的确不在里面。
这在过滤逻辑里也很常见。
比如:
filename = 'report.pdf'if'.exe'notin filename: print('不是可执行文件')
再比如:
comment = '这门课真不错'if'广告'notin comment: print('不是广告内容')
读起来也非常自然。
十九、find() 还能从指定位置开始找
这点很实用。
比如:
text = 'abcabcabc'print(text.find('abc'))
输出:
0
因为第一次出现就是从 0 开始。
但如果你想从后面继续找,就可以指定开始位置:
print(text.find('abc', 1))
输出:
3
意思是:
从索引 1 开始往后找,第一次找到的位置是 3
再看:
print(text.find('abc', 4))
输出:
6
这个在什么场景里有用?
比如你想找第二次出现的位置, 或者跳过前面的匹配结果继续往后找。
二十、find() 还能指定结束范围
除了起始位置,还可以写结束位置。
text = 'abcabcabc'print(text.find('abc', 0, 5))
这里的意思是:
只在索引 0 到 5 这个范围内找
这样可以限制搜索区域。
虽然新手阶段最常用的是:
find(内容)
或者:
find(内容, 开始位置)
但你知道它还能控制范围,后面处理复杂文本时会更从容。
二十一、实际场景一:判断文件类型
这个太经典了。
比如一批文件名:
filename = 'photo.jpg'
你想判断是不是图片:
if filename.endswith(('.jpg', '.png', '.gif')): print('图片文件')else: print('不是图片文件')
这比手动切片判断舒服太多。
特别是后缀种类一多,endswith() 的优势就很明显。
二十二、实际场景二:判断网址是否合法开头
比如:
url = 'https://www.example.com'
你想快速筛掉明显不合法的网址:
if url.startswith(('http://', 'https://')): print('看起来像网址')else: print('格式不对')
这种逻辑在爬虫、接口请求、表单校验里都很常见。
你会发现,startswith() 本质上就是规则过滤器。
二十三、实际场景三:判断邮箱格式里有没有 @
比如:
email = 'tom@example.com'
最粗略的判断方式之一就是:
if'@'in email: print('至少包含 @')else: print('格式明显不对')
当然,真正严格的邮箱校验没这么简单。 但入门阶段你先体会这个思路就够了:
很多格式判断,第一步就是看某个关键符号在不在。
而 in 正是做这件事的最自然工具。
二十四、实际场景四:从路径里找最后一个斜杠之后的内容
比如:
path = '/home/user/report.txt'
如果你想取出文件名,前提之一就是先知道最后的分隔符在哪里。 虽然这一章主讲的是 find(),严格说处理最后一个位置还有别的方法更顺手,后面会慢慢接触到。 但你现在要先建立一个意识:
文本提取往往分两步走。
第一步,先查找标记位置。 第二步,再切片拿内容。
比如这个思路在很多题里都适用:
找到 =找到 :找到 @找到 -找到 /
然后基于这个位置再做切片。
二十五、实际场景五:过滤日志里的错误信息
假设有这样一批日志:
log1 = 'INFO: 程序启动成功'log2 = 'ERROR: 文件读取失败'log3 = 'WARNING: 内存不足'
如果你只想看错误日志:
if log2.startswith('ERROR'): print('这是错误日志')
或者你想更宽松一点,只要包含 ERROR 就算:
if'ERROR'in log2: print('检测到错误')
你看,同样是判断,选择哪个方法,取决于你判断的是:
开头规则 还是只要包含就行
这就是方法之间最实际的区别。
二十六、find() 和切片经常组合使用
这点一定要专门感受一下。
比如你有这样一行配置:
text = 'name=zhangsan'
你想拿到等号后面的值。
最自然的步骤就是:
先找 = 在哪 再从后面切出来
代码:
text = 'name=zhangsan'pos = text.find('=')value = text[pos + 1:]print(pos)print(value)
输出:
4zhangsan
这就是很典型的字符串处理思路。
查找负责定位 切片负责提取
很多文本题其实都是这个套路。
二十七、最容易犯的几个错
先说第一个。
很多人会把 find() 返回的 0 误以为是假。
比如:
text = 'Python is good'pos = text.find('Python')print(pos)
输出是:
0
这不是没找到。 这是找到了,而且就在开头。
所以判断 find() 结果时,别写得太随意。 最稳的是明确判断:
if pos != -1: print('找到了')
第二个错,是把 in 和 find() 混着用。
如果只要真假,优先 in。 如果要位置,优先 find()。
第三个错,是以为 startswith() 和 endswith() 能判断中间内容。 不能。 它们只管开头和结尾。
第四个错,是大小写问题。
比如:
text = 'Python'print('python'in text)
输出是:
False
因为大小写不一样。
字符串判断默认是区分大小写的,这一点一定要记住。
二十八、大小写不同怎么办
如果你想忽略大小写再判断,通常要先统一大小写。
比如:
text = 'Python'print('python'in text.lower())
输出:
True
再比如判断文件后缀时,有的人会传 .JPG,有的人会传 .jpg。
那你就可以先统一转成小写:
filename = 'PHOTO.JPG'if filename.lower().endswith('.jpg'): print('这是 jpg 文件')
这在真实开发里非常重要。 因为很多脏数据、用户输入,大小写都不统一。
二十九、别把这些方法当成死知识,要把它们放进动作里理解
你真正要记住的,不是四个名字,而是四种动作。
判断开头 用 startswith()
判断结尾 用 endswith()
判断在不在 用 in
查找位置 用 find()
只要你把它们和动作绑定起来,后面遇到题目时就会自然很多。
看到文件后缀,脑子里蹦出 endswith()看到网址协议,脑子里蹦出 startswith()看到关键词过滤,脑子里蹦出 in看到要提取某个标记后面的内容,脑子里蹦出 find() 加切片
这才算真正学会。
三十、练习题:这一章一定要自己写一遍
下面这些练习非常有代表性,建议你自己先敲。
1. 判断 https://openai.com 是否以 https:// 开头
url = 'https://openai.com'print(url.startswith('https://'))
2. 判断 report.pdf 是否以 .pdf 结尾
filename = 'report.pdf'print(filename.endswith('.pdf'))
3. 判断 tom@example.com 中是否包含 @
email = 'tom@example.com'print('@'in email)
4. 查找 Python 在 I love Python 中第一次出现的位置
text = 'I love Python'print(text.find('Python'))
5. 判断 Java 是否不在 I love Python 中
text = 'I love Python'print('Java'notin text)
6. 判断 PHOTO.JPG 是否是 jpg 文件,忽略大小写
filename = 'PHOTO.JPG'print(filename.lower().endswith('.jpg'))
7. 找出 name=zhangsan 里等号的位置,并取出后面的值
text = 'name=zhangsan'pos = text.find('=')print(pos)print(text[pos + 1:])
你把这些题自己敲顺了,这一章的核心就基本吃透了。
三十一、本章小结
这一章你要带走的,不只是四个函数名,而是一整套字符串查找与判断思路。
startswith() 用来判断开头。endswith() 用来判断结尾。in 用来判断某段内容在不在。find() 用来定位某段内容第一次出现的位置。 找不到时,find() 返回 -1。 而字符串判断默认区分大小写,必要时要先统一大小写再处理。
更重要的是,你要开始形成一种处理文本的基本流程:
先判断 再定位 再切片 再提取
很多字符串问题,尤其是那些看起来有点像业务的小题,最后都会回到这条主线上。
下一章我们继续讲 字符串格式化入门:从 % 到 format。 到那一章,你会开始学习怎么把变量、数字、文本更优雅地塞进一段完整的话里,让输出不只是能跑,而且更整齐、更专业。