从长字符串中解析合法json结构的示例

当LLM输出包含json结构时,如何解析是一个比较难处理的问题,因为除json外还有常规文本。

虽然prompt约定按```json{xxx}```输出,LLM依然有可能忽略```json ```直接输出json的body。

这里参考网络资料,尝试示例集中健壮性比较好的从字符串提取json的解析方案。

1 直接解析

如果整个字符串就是 JSON,直接使用 json.loads() 解析,示例如下

复制代码
import json
text = '{"name": "Alice", "age": 30}'
data = json.loads(text)

2 字符串匹配

json body本质上是可解析字符串,所以也可以尝试字符串匹配方法,确定json body范围。

2.1 正则匹配

如果字符串中混杂 JSON 和其他文本,可以采用正则匹配的方法,示例代码如下

复制代码
import re, json
text = '前面一些文字 {"name": "Bob", "age": 25} 后面还有文字'
match = re.search(r'(\{.*\}|\[.*\])', text, re.DOTALL)
if match:
    json_str = match.group(1)
    data = json.loads(json_str)

适用于 JSON 不包含嵌套同类型括号,且没有转义干扰。

即无法正确处理嵌套结构,如对象内嵌对象或数组。

此时会匹配到第一个 { 到最后一个 },若中间有其他 {} 可能出错。

然而,实际测试显示,这种方案也能兼容部分此类情况。

嵌套和转义示例如下。

复制代码
import re, json
text = '前面一些文字 {"name": "Bo{{{b", "age": 25, "d{a{{d": {"dda": true}} 后面还有文字'
match = re.search(r'(\{.*\}|\[.*\])', text, re.DOTALL)
if match:
    json_str = match.group(1)
    data = json.loads(json_str)
    print(data)

输出示例如下

{'name': 'Bo{{{b', 'age': 25, 'd{a{{d': {'dda': True}}

2.2 括号匹配

手动扫描字符串,找到第一个 {[,然后使用计数器匹配对应的闭合括号。

档json比较规范时,括号匹配是一种有效方法。

然而当json的key或value包含{等字符时,该方法失效,示例代码如下。

复制代码
def extract_json(s):
    start = None
    stack = []
    for i, ch in enumerate(s):
        if ch in '{[':
            if not stack:
                start = i
            stack.append(ch)
        elif ch in '}]':
            if stack and ((ch == '}' and stack[-1] == '{') or (ch == ']' and stack[-1] == '[')):
                stack.pop()
                if not stack:
                    return s[start:i+1]
    return None

text = '一些文字 {"d{ata": [1,2,3], "ok}{{dsa": true} 结尾'

json_str = extract_json(text)
print(print(text))
if json_str:
    data = json.loads(json_str)
    print(data)

输出示例如下

一些文字 {"d{ata": 1,2,3, "ok}{{dsa": true} 结尾

None

所以不要仅凭计数 {} 来提取 JSON,除非完全确定字符串内不含花括号。

只要字符串可能包含结构字符,就必须使用真正的 JSON 解析器。

3 标准库方法

字符串匹配方法存在以上所述缺陷,这里进一步尝试标准库方法。

3.1 raw_decode方法

使用json标准库的的raw_decode方法,即用json.JSONDecoder.raw_decode解析。

raw_decode 可以从字符串开头解析 JSON,并返回解析后的对象和结束位置。

raw_decode要求 JSON 必须出现在字符串开头,否则需要先定位。

复制代码
import json

def extract_json_from_anywhere(s):
    decoder = json.JSONDecoder()
    # 依次从每个可能的位置尝试解析
    for i in range(len(s)):
        if s[i] in '{[':
            try:
                obj, end = decoder.raw_decode(s[i:])
                return obj
            except json.JSONDecodeError:
                continue
    return None

text = '前缀 {"valid": true, "dab": {"dd{d": 123, "sta}tus": true}} 后缀'
data = extract_json_from_anywhere(text)
print(data)

输出示例如下,可见此类方法能兼容特殊情况。

{'valid': True, 'dab': {'dd{d': 123, 'sta}tus': True}}

3.2 jsonfinder方法

jsonfinder是专门提取字符串中的 JSON的第三方库。

安装方法如下

pip install jsonfinder

示例代码如下

复制代码
from jsonfinder import jsonfinder

# 你的原始字符串
text = '前缀 {"name": "Alice", "age": 30}后缀'

# 使用 jsonfinder 迭代提取 JSON 对象
# 每次迭代会返回 (start_index, end_index, parsed_json_object)
for start, end, obj in jsonfinder(text):
    # obj 是已经用 json.loads() 解析好的 Python 对象(dict 或 list)
    if obj:
        print(text[start:end])
        print(f"找到了 JSON:{obj}")

输出如下,可见jsonfinder也能从字符串中提取正确的json数据。

{"name": "Alice", "age": 30}

找到了 JSON:{'name': 'Alice', 'age': 30}

reference


jsonfinder

https://github.com/alexmojaki/jsonfinder

在Python中读取大型JSON文件(raw_decode)

https://dev59.com/nYbca4cB1Zd3GeqPaMnZ

相关推荐
红叶舞18 小时前
成数据绑定对象,在应用程序中处理完数据后,将更新的数据序列化为JSON传回远端服务器,很多移动应用使用了这种模式处理服务器端的数据。 ...
运维·服务器·json
name好难取诶2 天前
解析请求体内容(如 JSON、表单数据、XML 等) 将原始数据转换为 Python 数据结构 使转换后的数据可在 request. ...
xml·python·json
gcw10242 天前
JSONMe 简觅JSON 工具
json·json格式化·json可视化·json美化·json校验·好用的json工具·json编辑
北北牌屈四巴格!2 天前
whistle自定义修改接口返回值内容
前端·json
SQDN2 天前
Chatbox 1.22.1 获取不到模型?先验 /models,再对齐精确 model ID
人工智能·测试工具·机器学习·chatgpt·json
SunnyDays10113 天前
Python 将 Excel(XLS/XLSX)转换为 JSON:导出工作簿、工作表、单元格区域与自定义 JSON 结构
python·json·excel·excel 转 json·导出 excel 到 json·xlsx 转 json·xls 转 json
刘小八3 天前
Spring AI 结构化输出:稳定生成可校验的业务 JSON
人工智能·spring·json
CodexDave4 天前
Python 自动化接单实战(一):把 CSV 需求做成配置驱动解析器
java·python·自动化·json·数据清洗·python自动化·csv处理
今夜有雨.5 天前
C++JSON 解析器
c++·笔记·后端·学习·json
用户657094163305 天前
Kotlin Moshi库 全面使用指南
json