当前位置: 首页 > news >正文

从字符串中提取 Document 的 page_content:手动拆还是用工具?

从字符串中提取 Document 的 page_content:手动拆还是用工具?

背景

继上一题的手拆字符串之后,又来了一个升级版:

字符串内容如下(为了阅读方便,我做了换行处理):

“[Document(metadata={‘pk’: 12, ‘page’: 2}, page_content=‘这里是第一段正文内容…’), Document(metadata={‘pk’: 27, ‘page’: 2}, page_content=‘这里是第二段正文内容…’), Document(metadata={‘pk’: 14, ‘page’: 3}, page_content=‘这里是第三段正文内容…’)]”

需求是:从这个字符串中提取每个 Document 的 page_content(正文内容),然后拼接成一个完整的字符串。

这道题的核心考点是:给定一个包含对象的字符串,如何安全地提取其中的特定字段(page_content)。

思路一:纯手动拆分(正则表达式)

既然字符串有固定格式:Document(metadata={‘pk’: 数字, ‘page’: 数字}, page_content=‘这里是正文…’)

我们可以直接用正则表达式提取 page_content 后面的内容:

import re raw_str = "[Document(metadata={'pk': 12, 'page': 2}, page_content='这里是第一段正文内容...'), Document(metadata={'pk': 27, 'page': 2}, page_content='这里是第二段正文内容...'), Document(metadata={'pk': 14, 'page': 3}, page_content='这里是第三段正文内容...')]" # 提取 page_content 后面的内容 contents = re.findall(r"page_content='(.*?)'", raw_str) # 拼接成完整字符串 result = "".join(contents) print(result) # 输出: 这里是第一段正文内容...这里是第二段正文内容...这里是第三段正文内容...

优点

  • 代码短,思路直接
  • 不需要额外库(re 是标准库)

缺点

  • 极其脆弱:如果正文里包含单引号,正则就会失效
  • 不通用:换一种对象结构就得重写正则
  • 如果 page_content 的值包含换行或特殊字符,代码立刻报错

思路二:用 ast.literal_eval 解析(更安全)

如果我们能把字符串转成 Python 对象,然后直接访问 page_content 属性,那就安全得多。

但问题来了:ast.literal_eval 不认识 Document 这个类名,所以不能直接解析。

解决思路:把 Document(…) 替换成字典 {…}

import re import ast raw_str = "[Document(metadata={'pk': 12, 'page': 2}, page_content='这里是第一段正文内容...'), Document(metadata={'pk': 27, 'page': 2}, page_content='这里是第二段正文内容...'), Document(metadata={'pk': 14, 'page': 3}, page_content='这里是第三段正文内容...')]" # 提取 metadata 和 page_content pattern = r"Document\(metadata=({.*?}), page_content='(.*?)'\)" matches = re.findall(pattern, raw_str) contents = [] for metadata_str, content in matches: contents.append(content) # content 就是 page_content 的值 result = "".join(contents) print(result) # 输出: 这里是第一段正文内容...这里是第二段正文内容...这里是第三段正文内容...

优点

  • 解析的是 Python 字面量,安全可靠
  • 能处理稍微复杂的格式变化(只要 metadata 部分合法)

缺点

  • 代码比纯正则稍复杂
  • 如果 page_content 里有单引号,仍然会出问题

思路三:针对 page_content 包含特殊字符的终极方案

如果 page_content 里面可能包含单引号、换行等特殊字符,上面的正则就失效了。

这时候需要更精确的匹配策略:

import re import ast raw_str = "[Document(metadata={'pk': 12, 'page': 2}, page_content='第一段正文...'), Document(metadata={'pk': 27, 'page': 2}, page_content='第二段正文...')]" # 用正则提取 metadata 部分,再单独提取 page_content pattern = r"Document\(metadata=({.*?}), page_content='(.*?)'\)" matches = re.findall(pattern, raw_str) contents = [] for metadata_str, content in matches: # 如果 content 里有转义字符,用 ast.literal_eval 安全还原 try: # 把 content 当作 Python 字符串字面量解析 safe_content = ast.literal_eval(f"'{content}'") contents.append(safe_content) except: contents.append(content) result = "".join(contents)

思路四:如果题目给的是对象列表(最理想情况)

如果题目不是给你一个字符串,而是给你一个已经存在的 documents 列表,那就直接操作对象即可:

contents = [doc.page_content for doc in documents] result = "".join(contents)

这是最简单、最直接、最安全的方式。

这道题在考试中的正确答法

  1. 如果题目明确说"这是一个字符串":用 ast.literal_eval 配合 re.findall 提取 page_content 字段,然后拼接。
  2. 如果题目说"有一个 documents 列表":直接用列表推导式 [doc.page_content for doc in documents]。
  3. 如果 page_content 可能包含特殊字符(如引号、换行),用 ast.literal_eval 做二次安全解析。

总结一句话

手动拆分是"能做到",但正确做法是"安全解析"。考试看的是你对工具的理解,不是你折腾字符串的能力。

三种方式对比

方式代码量安全性通用性推荐度
纯正则手拆极低极低不推荐
ast.literal_eval + 正则推荐
直接操作对象列表极高极高最推荐

彩蛋:如果 page_content 包含换行或特殊字符怎么办?

如果正文内容可能包含换行或特殊字符,上面的方法仍然可以处理,因为 ast.literal_eval 能安全解析 Python 字符串字面量。

但如果正文内容非常长,或者包含各种特殊符号,最稳妥的方式是在字符串生成时就做好序列化,而不是在解析时临时处理。

http://www.jsqmd.com/news/1370169/

相关文章:

  • WebAssembly沙箱:为AI Agent构建安全高效执行环境的技术实践
  • 双向链表(头插、尾插、查找、修改、头删、尾删、删除指定节点、链表长度、销毁)
  • Claude Code 智能体架构解析:从任务规划到安全执行的AI编程伙伴
  • Unity UGUI性能优化:CanvasUpdateRegistry重建机制与实战分析
  • 无人机实训高成本痛点解法:虚拟仿真实现 70% 耗材损耗下降
  • 涛涛车业扩建泰国电动高尔夫球车与全地形车基地
  • Qoder Browser Use:为AI Agent打造可靠浏览器操作环境的技术解析与实践
  • 构建现代终端工作流:Alacritty、Zellij与Zinit的极客组合
  • 工程师必读:从Tokenization到Attention,深入理解LLM核心原理与工程实践
  • Matplotlib图表深度解析:从折线图到子图布局的Python数据可视化实战
  • Windows 10资源管理器卡死终极排查:从外壳扩展到系统文件的修复指南
  • 采购合同电子签有法律效力吗?供应商远程这样签最稳
  • SpringBoot+Vue博客系统集成协同过滤推荐算法实战
  • 涂胶显影行业中级工程师综合人才评估报告(六大核心维度)
  • Zabbix 5.0 从零部署指南:环境规划、安装配置与监控实战
  • Hive JSON解析性能优化:get_json_object与json_tuple函数深度对比与选型指南
  • Java守护线程:后台服务的生命周期管理与实战应用
  • Java技术栈的现状与转型实战指南
  • C++条件变量虚假唤醒:原理、解决方案与线程安全队列实战
  • NVIDIA NeMo Retriever:企业级多模态RAG框架实战指南
  • 技术面试中的防忽悠指南与实战案例分析
  • Python小提琴图实战:从核密度估计到数据洞察的完整指南
  • 从零自制全能游戏U盘:基于Batocera打造便携复古游戏系统
  • Open UI5键盘交互机制与优化实践
  • Claude Code多智能体协作:构建AI驱动的软件开发团队
  • 如何评估早期开源项目:从概念到可运行原型的系统性框架
  • 单片机全方位调试实战指南:串口/RTT/逻辑分析仪/示波器/内核排错分层避坑教程
  • DLNA投屏 | Windows无线投屏工具
  • 从开题到答辩AI工具红黑榜:26届实测经验
  • 使用Scrapy框架爬取图书网站并存入MongoDB——从零到部署的完整实战指南