
本文详解如何将结构化文本文件(如含154首十四行诗的sonnets.txt)系统性地解析为Python三维列表:sonnets[sonnet_idx][line_idx][word_idx],支持精准定位任意诗句中的任意单词,并自动清除标点、处理多空行分隔、忽略编号标题。
本文详解如何将结构化文本文件(如含154首十四行诗的`sonnets.txt`)系统性地解析为Python三维列表:`sonnets[sonnet_idx][line_idx][word_idx]`,支持精准定位任意诗句中的任意单词,并自动清除标点、处理多空行分隔、忽略编号标题。
要实现类似 sonnets[1][4][2](即第2首诗、第5行、第3个词)的直观索引访问,关键在于分层切分:先按“诗”划分,再在每首诗内按“行”切分,最后对每行按“词”切分。由于原始文件中诗与诗之间以空行+罗马数字标题(如 I.、II.)分隔,而诗内行为标准换行,不能简单用 split('\n') 一维处理——必须识别并跳过标题行,同时利用空行作为诗间边界。
以下为完整、鲁棒的实现方案:
✅ 步骤一:按诗分割(核心难点)
使用正则表达式 re.split() 精准捕获诗间分隔符。观察样本可知,每首诗前有形如 I.\n\n 或 II.\n\n 的模式(标题行 + 双换行)。我们匹配:
-
(?:\n\n|^):行首或双换行; -
.*\.\n\n:任意字符结尾于英文句点,后跟双换行。
import re
import string
with open("sonnets.txt", "r", encoding="utf-8") as f:
data = f.read()
# 拆分诗集(保留空行分隔逻辑)
sonnets = re.split(r'(?:\n\n|^).*\.\n\n', data)
sonnets = [s.strip() for s in sonnets if s.strip()] # 清除空项和首尾空白
⚠️ 注意:
re.split会在匹配处切割,导致首项为空字符串(因文件以I.\n\n开头),故需过滤空项。
✅ 步骤二:逐诗清理与分行
对每首诗:
- 移除所有标点(使用
str.translate()高效替代循环); - 按行分割(
splitlines()自动处理\n/\r\n); - 过滤空行(避免因多余空行产生空列表)。
# 构建标点映射表(Unicode码点 → None)
xlat = str.maketrans('', '', string.punctuation)
for i, sonnet in enumerate(sonnets):
# 去标点 + 分行 + 去空行
cleaned_lines = sonnet.translate(xlat).splitlines()
cleaned_lines = [line.strip() for line in cleaned_lines if line.strip()]
# 每行再拆分为单词列表
sonnets[i] = [line.split() for line in cleaned_lines]
✅ 最终结构验证
此时 sonnets 是一个三维列表:
-
len(sonnets)→ 诗的数量(应为154); -
len(sonnets[0])→ 第1首诗的行数(应为14); -
len(sonnets[0][0])→ 第1首第1行的单词数(如'FROM fairest creatures...'→['FROM', 'fairest', 'creatures'])。
可直接索引:
print(sonnets[1][2][3]) # 输出: 'livery'(第2首诗,第3行,第4个词)
? 补充技巧与健壮性增强
-
编码兼容性:务必指定
encoding='utf-8',避免Windows系统下乱码; -
大小写处理:如需不区分大小写搜索,可在拆词后统一
.lower(); -
特殊符号残留:
string.punctuation不包含中文标点或破折号(—)、省略号(…),若需更全面清洗,可扩展为:import re def clean_text(text): return re.sub(r'[^\w\s]', '', text) # 仅保留字母、数字、下划线、空白 - 内存优化:对超大文件,可用生成器逐诗处理,避免一次性加载全部文本。
✅ 总结
该方法将非结构化文学文本转化为可编程索引的三维数据结构,兼顾准确性与可读性。其核心思想是:用正则识别语义边界(诗),用字符串方法净化内容(去标点),用嵌套列表推导构建层级(行→词)。掌握此模式,可快速适配其他类似任务——如解析实验日志、古籍章回、法律条文等具有“块-行-字段”三级结构的文本。










