当前位置: 代码网 > it编程>前端脚本>Python > Python中两种“伪列表“字符串的解析技巧详解

Python中两种“伪列表“字符串的解析技巧详解

2026年09月10日 Python 我要评论
在 python 开发中,我们经常会遇到看起来像 list,但实际是 str 的数据。本文通过两道实战题目,带你掌握两种不同场景下的解析方法。一、引言你是否遇到过这样的情况:data = '["qwe

在 python 开发中,我们经常会遇到看起来像 list,但实际是 str 的数据。本文通过两道实战题目,带你掌握两种不同场景下的解析方法。

一、引言

你是否遇到过这样的情况:

data = '["qwen-turbo","qwen-plus","deepseek"]'
print(type(data))  # <class 'str'> ???

明明看起来是个列表,为什么类型是字符串?

更头疼的是,有时候字符串里还包含自定义对象,比如 langchain 的 document

data = "[document(metadata={'pk': 12, 'page': 2}, page_content='...')]"

这两种情况,解析方法完全不同!本文通过两道题,带你彻底搞懂。

二、第一题:标准格式字符串转列表

2.1 题目

raw_str = '["qwen-turbo","qwen-plus","deepseek"]'
# 将其转换为 list

2.2 分析

这是一个标准的 json 格式字符串,内容是字符串数组。

2.3 解决方案

方法一:json.loads()(推荐)

import json

raw_str = '["qwen-turbo","qwen-plus","deepseek"]'
result = json.loads(raw_str)

print(result)       # ['qwen-turbo', 'qwen-plus', 'deepseek']
print(type(result)) # <class 'list'>

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

方法二:ast.literal_eval()

import ast

raw_str = '["qwen-turbo","qwen-plus","deepseek"]'
result = ast.literal_eval(raw_str)

print(result)       # ['qwen-turbo', 'qwen-plus', 'deepseek']
print(type(result)) # <class 'list'>

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

方法三:eval()(不推荐)

raw_str = '["qwen-turbo","qwen-plus","deepseek"]'
result = eval(raw_str)

print(result)       # ['qwen-turbo', 'qwen-plus', 'deepseek']

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

2.4 三种方法对比

方法速度安全性适用场景
json.loads()⭐⭐⭐ 最快⭐⭐ 安全json 格式字符串
ast.literal_eval()⭐⭐ 一般⭐⭐⭐ 最安全python 字面量格式
eval()⭐⭐ 一般⭐ 危险不推荐使用

三、第二题:对象格式字符串提取字段

3.1 题目

raw_str = """[document(metadata={'pk': 12, 'page': 2}, page_content='2. 费⽤报销:业务活动中产⽣的费⽤...'),
document(metadata={'pk': 27, 'page': 2}, page_content='2. 费⽤报销:业务活动中产⽣的费⽤...'),
document(metadata={'pk': 14, 'page': 3}, page_content='3. 最后警告:情节严重,留司察看...')]"""

# 问题:如何获取里面的 page 属性?

3.2 分析

这个字符串包含 langchain 的 document 对象,它不是标准 json,而是 python 的 repr() 输出格式。

为什么 json.loads() 不行?

import json
json.loads(raw_str)  # ❌ 报错!json.decoder.jsondecodeerror

原因:

  1. 字符串中使用了单引号 ',json 要求双引号 "
  2. 包含 document(...) 这种自定义对象,不是 json 支持的数据类型

为什么 ast.literal_eval() 也不行?

import ast
ast.literal_eval(raw_str)  # ❌ 报错!valueerror: malformed node

原因:ast.literal_eval() 只能解析 python 字面量(字符串、数字、列表、字典等),不能解析函数调用 document(...)

3.3 解决方案:正则表达式

import re
from collections import defaultdict

raw_str = "[document(metadata={'pk': 12, 'page': 2}, page_content='...'), ...]"

# 方法1:只提取 page
pages = re.findall(r"'page':\s*(\d+)", raw_str)
pages = [int(p) for p in pages]
print(pages)  # [2, 2, 3]

# 方法2:提取 page + 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[page])
    print(f"=== 第 {page} 页 ===")
    print(combined)
    print()

3.4 正则表达式解析

r"'page':\s*(\d+)"
部分含义
'page':匹配字面量 'page':
\s*匹配 0 或多个空白字符
(\d+)捕获 1 或多个数字(这是我们想要的)
r"document\(metadata=\{.*?'page':\s*(\d+).*?page_content='(.*?)'\)"
部分含义
document\(匹配 document(
metadata=\{匹配 metadata={
.*?非贪婪匹配任意字符
'page':\s*(\d+)捕获 page 的值
page_content='(.*?)'捕获 page_content 的内容
\)匹配 )

四、完整代码

4.1 第一题完整代码

import json
import ast

def parse_json_list(raw_str: str) -> list:
    """解析 json 格式的字符串列表"""
    return json.loads(raw_str)

def parse_python_list(raw_str: str) -> list:
    """解析 python 字面量格式的字符串列表"""
    return ast.literal_eval(raw_str)

# 测试
raw_str = '["qwen-turbo","qwen-plus","deepseek"]'

result1 = parse_json_list(raw_str)
result2 = parse_python_list(raw_str)

print(f"json.loads: {result1}")
print(f"ast.literal_eval: {result2}")

4.2 第二题完整代码

import re
from collections import defaultdict

def extract_pages(raw_str: str) -> list:
    """从 document 字符串中提取所有 page"""
    return [int(p) for p in re.findall(r"'page':\s*(\d+)", raw_str)]

def extract_docs_by_page(raw_str: str) -> dict:
    """从 document 字符串中提取 page 和 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)

    return dict(page_contents)

def combine_by_page(raw_str: str) -> str:
    """按页码拼接所有内容"""
    page_contents = extract_docs_by_page(raw_str)

    result = []
    for page in sorted(page_contents.keys()):
        combined = "\n".join(page_contents[page])
        result.append(f"=== 第 {page} 页 ===\n{combined}")

    return "\n\n".join(result)

# 测试
raw_str = """[document(metadata={'pk': 12, 'page': 2}, page_content='2. 费⽤报销...'),
document(metadata={'pk': 27, 'page': 2}, page_content='2. 费⽤报销...'),
document(metadata={'pk': 14, 'page': 3}, page_content='3. 最后警告...')]"""

print("提取的页码:", extract_pages(raw_str))
print("\n按页拼接结果:")
print(combine_by_page(raw_str))

五、对比总结

对比项第一题(纯数据)第二题(对象格式)
字符串格式json 标准格式python repr 格式
数据类型基本类型(字符串、数字)自定义对象(document)
引号类型双引号 "单引号 '
能否用 json.loads()✅ 能❌ 不能
能否用 ast.literal_eval()✅ 能❌ 不能
能否用 eval()✅ 能⚠️ 需要 import document
推荐方案json.loads()re.findall()

选型建议

遇到字符串形式的"列表"?
    │
    ├─ 是标准 json 格式? → json.loads()
    │
    ├─ 是 python 基本字面量? → ast.literal_eval()
    │
    └─ 包含自定义对象? → 正则表达式提取

六、常见问题

q1:为什么不推荐 eval()?

eval() 会执行任意 python 代码,存在安全风险:

# 恶意输入
malicious = "__import__('os').system('rm -rf /')"
eval(malicious)  # 💀 危险!

q2:正则表达式太难了,有更简单的方法吗?

如果字符串格式固定,也可以用字符串分割:

# 简单粗暴的方法
pages = []
for part in raw_str.split("'page': "):
    if part and part[0].isdigit():
        pages.append(int(part.split(",")[0]))

但正则更通用、更可靠。

q3:langchain 的 document 对象为什么不是标准 json?

因为 document 是 python 类,它的 repr() 输出是 python 语法,不是 json。这是 python 对象序列化的常见问题。

七、总结

  1. 标准格式用标准工具:json 字符串用 json.loads()
  2. 复杂格式用正则:包含自定义对象的字符串,正则是最佳选择
  3. 安全第一:避免使用 eval(),除非你能完全信任输入源

掌握这两种技巧,以后再遇到"看起来像 list 的字符串",就不会懵了!

到此这篇关于python中两种“伪列表“字符串的解析技巧详解的文章就介绍到这了,更多相关python字符串解析内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com