查看: 364|回复: 0

Python伪列表字符串解析:json.loads与正则提取

[复制链接]
发表于 3 小时前 | 显示全部楼层 |阅读模式
在 Python 开发中,经常遇到看起来像 list、实际类型是 str 的数据。例如接口或日志里出现:
  1. data = '["qwen-turbo","qwen-plus","deepseek"]'
  2. print(type(data))  # <class 'str'>
复制代码

另一种是包含自定义对象的 repr 字符串,例如 LangChain 的 Document:
  1. data = "[Document(metadata={'pk': 12, 'page': 2}, page_content='...')]"
复制代码

这两类字符串的解析方式不同:标准 JSON 数组可以用 json.loads(),而 Python 对象 repr 字符串需要正则提取字段。下面按两种场景说明。

一、标准 JSON 格式字符串转列表
题目:
  1. raw_str = '["qwen-turbo","qwen-plus","deepseek"]'
  2. # 将其转换为 list
复制代码

这是标准 JSON 格式字符串,内容是字符串数组。

方法一:json.loads() 推荐
  1. import json
  2. raw_str = '["qwen-turbo","qwen-plus","deepseek"]'
  3. result = json.loads(raw_str)
  4. print(result)       # ['qwen-turbo', 'qwen-plus', 'deepseek']
  5. print(type(result)) # <class 'list'>
复制代码

优点:速度快,标准库支持,JSON 格式通用性强。

方法二:ast.literal_eval()
  1. import ast
  2. raw_str = '["qwen-turbo","qwen-plus","deepseek"]'
  3. result = ast.literal_eval(raw_str)
  4. print(result)       # ['qwen-turbo', 'qwen-plus', 'deepseek']
  5. print(type(result)) # <class 'list'>
复制代码

优点:安全性高,只解析字面量,不会执行恶意代码。

方法三:eval() 不推荐
  1. raw_str = '["qwen-turbo","qwen-plus","deepseek"]'
  2. result = eval(raw_str)
  3. print(result)       # ['qwen-turbo', 'qwen-plus', 'deepseek']
复制代码

缺点:会执行任意 Python 代码,有安全风险,生产环境慎用。

三种方法对比:json.loads() 速度最快、安全性较好,适合 JSON 格式字符串;ast.literal_eval() 速度一般、最安全,适合 Python 字面量格式;eval() 速度一般、危险,不推荐使用。

二、对象格式字符串提取字段
题目:
  1. raw_str = """[Document(metadata={'pk': 12, 'page': 2}, page_content='2. 费⽤报销:业务活动中产⽣的费⽤...'),
  2. Document(metadata={'pk': 27, 'page': 2}, page_content='2. 费⽤报销:业务活动中产⽣的费⽤...'),
  3. Document(metadata={'pk': 14, 'page': 3}, page_content='3. 最后警告:情节严重,留司察看...')]"""
复制代码

问题是:如何获取里面的 page 属性,并按页码组织 page_content?

这个字符串包含 LangChain 的 Document 对象。它不是标准 JSON,而是 Python 的 repr() 输出格式。

为什么 json.loads() 不行?因为字符串中使用单引号,JSON 要求双引号;Document(...) 这种自定义对象也不是 JSON 支持的数据类型。调用 json.loads(raw_str) 会报 json.decoder.JSONDecodeError。

为什么 ast.literal_eval() 也不行?因为它只能解析 Python 字面量,例如字符串、数字、列表、字典等,不能解析函数调用 Document(...)。调用 ast.literal_eval(raw_str) 会报 ValueError: malformed node。

解决方案是使用正则表达式。

方法 1:只提取 page
  1. import re
  2. raw_str = "[Document(metadata={'pk': 12, 'page': 2}, page_content='...'), ...]"
  3. pages = re.findall(r"'page':\s*(\d+)", raw_str)
  4. pages = [int(p) for p in pages]
  5. print(pages)  # [2, 2, 3]
复制代码

正则含义:'page': 匹配字面量;\s* 匹配 0 个或多个空白字符;(\d+) 捕获 1 个或多个数字。

方法 2:提取 page 和 page_content,并按页分组

[code]
import re
from collections import defaultdict

raw_str = "[Document(metadata={'pk': 12, 'page': 2}, page_content='...'), ...]"
docs = re.findall(
    r"Document\(metadata=\{.*?'page':\s*(\d+).*?page_content='(.*?)'\)",
    raw_str,
    re.DOTALL
)

page_contents = defaultdict(list)
for page, content in docs:
    page_contents[int(page)].append(content)

for page in sorted(page_contents.keys()):
    combined = "\n".join(page_contents
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-10 16:38 , Processed in 0.028171 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部