在Python中处理文本文件是一项非常基础也极其常用的任务。当我们需要从一个拥有成百上千行内容的文件里,找出所有包含某个或某些关键词的行,并将其打印出来时,最直观也最高效的做法就是利用Python的文件迭代能力与字符串操作方法。这种方式不需要借助第三方库,标准库就能完成,而且内存占用低,逻辑清晰,适合新手快速上手以及在生产脚本中稳定运行。

一、基础实现:逐行读取并匹配关键词
Python的文件对象本身就是一个可迭代对象,这意味着我们可以直接用for循环去遍历它,每次循环拿到的是文件中的一行字符串,包括末尾的换行符。在这样的一行文本上,我们可以使用字符串类型的find方法或者in关键字来判断是否包含目标关键词。
使用in是最符合人类直觉的写法,语义清晰;而find方法在需要得知关键词出现位置时更有用,返回值为-1表示未找到。下面给出一个最简单的示例,从当前目录下的test.txt中找出所有包含error这个词的行并打印行号与内容。
# 打开文件,使用utf-8编码避免中文乱码
with open('test.txt', 'r', encoding='utf-8') as f:
# 行号从1开始计数更符合阅读习惯
line_num = 1
for line in f:
# 判断关键词是否在当前行中
if 'error' in line:
# end=''是因为line本身已带换行符
print(f'第{line_num}行: {line}', end='')
line_num += 1
上面的代码采用了with语句来管理文件资源,这样无论读取过程中是否出现异常,文件都会被正确关闭,避免句柄泄露。逐行迭代的方式不会一次性把整个文件加载进内存,对于几个GB的日志文件也能平稳处理。
需要注意的是,从文件读出的每一行末尾通常都带有换行符n,如果我们用print函数再默认追加一个换行,就会在终端里出现空行间隔。所以在示例中用了end=''来抑制额外换行,让输出版式和原文件保持一致。
二、忽略大小写与多关键词匹配
实际业务里,关键词可能以不同大小写形式出现,比如Error、ERROR、error。如果直接用in判断就会漏掉非小写的情况。我们可以把每行文本和关键词都统一转成小写再比较,这样就能实现简单的忽略大小写查找。
另外,有时我们不是找单个词,而是想找出包含多个词语中任意一个的行,或者必须同时包含几个词。前者可以用元组配合any,后者用all。下面代码演示了忽略大小写并且支持多关键词或逻辑匹配的做法。
keywords = ['error', 'warn', 'fail']
with open('test.txt', 'r', encoding='utf-8') as f:
for idx, line in enumerate(f, start=1):
# 统一转小写,避免大小写遗漏
low_line = line.lower()
# 任意一个关键词出现即命中
if any(k in low_line for k in keywords):
print(f'第{idx}行: {line}', end='')
这段脚本把关键词列表放在keywords里,方便后期维护。通过生成器表达式配合any,代码依旧保持简洁且运行高效。如果需求改成“同时包含error和warn才算匹配”,只需要把any换成all即可,其余结构不用动。
这种写法在处理运维日志时特别实用,比如想一次性把警告和错误级别的信息全捞出来排查问题,而不用反复跑几次脚本。它也比写一堆or条件判断要优雅很多,后续加关键词只改列表就行。
三、使用正则表达式处理复杂模式
当关键词不是固定字符串,而是某种规律,比如“以日期开头且带error”,或者“包含邮箱格式”,基础的in就力不从心了。此时应当请出标准库中的re模块。正则提供了强大的模式描述能力,而且re模块同样可以和逐行读取很好配合。
我们可以用re.compile先编译好正则对象提升性能,再在每行上用search方法查找。下面例子找出所有符合“三个数字-三个数字”这种简易编号格式并且后面带error的行。
import re
# 编译正则:匹配形如 123-456 后接 error 的行片段
pattern = re.compile(r'd{3}-d{3}.*error')
with open('test.txt', 'r', encoding='utf-8') as f:
for idx, line in enumerate(f, start=1):
if pattern.search(line):
print(f'匹配行{idx}: {line}', end='')
正则方案虽然灵活,但代价是代码可读性对初学者稍低,且复杂正则若写得不好会有回溯灾难导致变慢。因此日常简单包含判断完全没必要上正则,只有真正涉及模式匹配时才引入,做到因地制宜。
此外,如果文件编码不是utf-8,比如老旧系统生成的gbk日志,只需把open里的encoding参数改为'gbk'即可,否则会抛出解码异常。这也是实战中容易踩的小坑。
四、将结果写入新文件而非仅打印
打印到屏幕适合临时查看,但若想把筛出的行永久保存,就要把结果写到另一个文件。逻辑和打印几乎一样,只是把print换成对输出文件的write。下面示例把命中行写入result.txt。
with open('test.txt', 'r', encoding='utf-8') as src,
open('result.txt', 'w', encoding='utf-8') as dst:
for idx, line in enumerate(src, start=1):
if 'error' in line:
# 写文件时line已带换行,直接写即可
dst.write(f'第{idx}行: ' + line)
利用上下文管理器同时打开两个文件,代码紧凑且安全。写入时我们手动加了行号前缀,方便后续定位原文件位置。如果结果文件还要给别的程序读,也可以不加前缀只保留原始行,视具体需要决定。
整体来看,Python在多行文本中按关键词查行属于“小问题大用处”的典型场景。从最简单的in判断,到忽略大小写、多关键词,再到正则与结果持久化,难度平滑上升,却能覆盖绝大多数日常文本处理需求。理解并熟练运用文件迭代与字符串方法,是写好各类自动化小工具的第一步。