Python中解析非标准格式的多重JSON对象流


Python中解析非标准格式的多重JSON对象流

本教程旨在解决接收到多个json对象以非标准格式(即没有外部数组括号和逗号分隔)直接连接的场景。我们将介绍一种python解析策略,通过识别json对象的结束和开始标记来精确分割数据流,从而实现对每个独立json对象的成功解析和处理。

理解非标准JSON数据流

在处理API响应或日志数据时,我们通常期望接收到符合RFC 8259标准的JSON格式,例如单个JSON对象或一个包含多个JSON对象的数组。然而,在某些情况下,可能会遇到一种非标准的数据流,其中多个独立的JSON对象直接连接在一起,没有外部的方括号 [] 包裹,也没有逗号 , 进行分隔。这种格式使得标准的 json.loads() 函数无法直接解析整个字符串,因为它不是一个有效的JSON文档。

以下是一个典型的非标准JSON数据流示例:

{
"self": "https://example1.com",
"key": "keyOne",
"name": "nameOne",
"emailAddress": "mailOne",
"*atarUrls": { /* ... */ },
"displayName": "displayNameOne",
"active": true,
"timeZone": "Europe",
"locale": "en_UK"
}
{
"self": "https://example2.com",
"key": "keyTwo",
"name": "nameTwo",
"emailAddress": "mailTwo",
"*atarUrls": { /* ... */ },
"displayName": "displayNameTwo",
"active": false,
"timeZone": "Europe",
"locale": "en_US"
}

在这种结构中,一个JSON对象的结束符 } 之后紧跟着下一个JSON对象的开始符 {,它们之间可能只有换行符。我们的目标是识别这些边界,并将数据流分割成独立的、可解析的JSON字符串。

解析策略:基于行识别边界

由于每个JSON对象都是一个独立的实体,其结束标志是 },而下一个对象的开始标志是 {。我们可以利用这一特性,逐行扫描整个数据流。当检测到当前行是 { 并且前一行是 } 时,就意味着我们找到了两个JSON对象之间的边界。

具体的解析步骤如下:

芦笋演示 芦笋演示

一键出成片的录屏演示软件,专为制作产品演示、教学课程和使用教程而设计。

芦笋演示 227 查看详情 芦笋演示
  1. 将整个非标准JSON数据流按行分割。
  2. 遍历这些行,维护一个当前正在构建的JSON对象的起始索引。
  3. 当发现一个行以 } 结束,并且紧接着的下一行以 { 开始时,这表明前一个完整的JSON对象已经结束。此时,将从起始索引到当前行(包含)的所有行拼接起来,形成一个完整的JSON字符串。
  4. 使用 json.loads() 函数解析这个字符串,并将其添加到结果列表中。
  5. 更新起始索引为当前行的下一行,继续处理剩余数据。
  6. 处理完所有行后,最后一个JSON对象需要单独处理。

Python实现示例

下面是使用Python实现上述解析策略的示例代码:

import json

# 示例非标准JSON数据流
data_stream = '''
{
"self": "https://example1.com",
"key": "keyOne",
"name": "nameOne",
"emailAddress": "mailOne",
"*atarUrls": {
  "48x48": "https://test.com/secure/user*atar?*atarId=1",
  "24x24": "https://test.com/secure/user*atar?size=small&*atarId=1",
  "16x16": "https://test.com/secure/user*atar?size=xsmall&*atarId=1",
  "32x32": "https://test.com/secure/user*atar?size=medium&*atarId=1"
},
"displayName": "displayNameOne",
"active": true,
"timeZone": "Europe",
"locale": "en_UK"
}
{
"self": "https://example2.com",
"key": "keyTwo",
"name": "nameTwo",
"emailAddress": "mailTwo",
"*atarUrls": {
  "48x48": "https://test.com/secure/user*atar?*atarId=2",
  "24x24": "https://test.com/secure/user*atar?size=small&*atarId=2",
  "16x16": "https://test.com/secure/user*atar?size=xsmall&*atarId=2",
  "32x32": "https://test.com/secure/user*atar?size=medium&*atarId=2"
},
"displayName": "displayNameTwo",
"active": false,
"timeZone": "Europe",
"locale": "en_US"
}
'''

def parse_concatenated_json(data_string: str) -> list:
    """
    解析包含多个直接连接的非标准JSON对象的字符串。

    Args:
        data_string: 包含非标准JSON对象流的字符串。

    Returns:
        一个包含所有解析出的JSON字典的列表。
    """
    json_objects = []
    lines = data_string.strip().splitlines() # 移除首尾空白并按行分割

    current_object_start_line = 0 # 记录当前JSON对象开始的行索引

    for i, line in enumerate(lines):
        # 检查当前行是否为"{"且前一行是否为"}"
        # 并且确保不是第一个JSON对象的开始(i > 0)
        if i > 0 and line.strip() == "{" and lines[i-1].strip() == "}":
            # 找到一个JSON对象的边界,解析前一个对象
            json_segment = "\n".join(lines[current_object_start_line:i])
            try:
                json_objects.append(json.loads(json_segment))
            except json.JSONDecodeError as e:
                print(f"解析JSON片段失败: {e}\n片段内容:\n{json_segment}")
                # 根据实际需求选择是跳过、记录错误还是中断
                pass
            # 更新下一个JSON对象的起始行
            current_object_start_line = i

    # 处理最后一个JSON对象
    if current_object_start_line < len(lines):
        json_segment = "\n".join(lines[current_object_start_line:])
        try:
            json_objects.append(json.loads(json_segment))
        except json.JSONDecodeError as e:
            print(f"解析最后一个JSON片段失败: {e}\n片段内容:\n{json_segment}")

    return json_objects

# 调用解析函数
parsed_data = parse_concatenated_json(data_stream)

# 打印解析结果以验证
print(f"成功解析 {len(parsed_data)} 个JSON对象:")
for obj in parsed_data:
    print(json.dumps(obj, indent=2, ensure_ascii=False)) # 格式化输出,方便阅读

代码解析:

  1. data_stream.strip().splitlines(): 首先使用 strip() 移除整个字符串开头和结尾的空白字符(包括换行),然后使用 splitlines() 将字符串分割成一个行的列表。
  2. current_object_start_line: 这个变量用于标记当前正在构建的JSON对象的起始行索引。
  3. for i, line in enumerate(lines): 遍历每一行及其索引。
  4. if i > 0 and line.strip() == "{" and lines[i-1].strip() == "}": 这是核心判断逻辑。它检查:
    • i > 0: 确保不是数据流的起始,因为第一个JSON对象之前没有 }。
    • line.strip() == "{": 当前行去除空白后是否为 {。
    • lines[i-1].strip() == "}": 前一行去除空白后是否为 }。
    • 如果这三个条件都满足,则表明我们已经跨越了一个完整的JSON对象的边界。
  5. json_segment = "\n".join(lines[current_object_start_line:i]): 将从上一个起始行到当前行之前的所有行拼接起来,形成一个完整的JSON字符串。使用 "\n".join() 保持原始的换行符,这对于 json.loads 解析多行JSON字符串是必要的。
  6. json.loads(json_segment): 使用Python内置的 json 模块解析这个片段。
  7. current_object_start_line = i: 更新起始行索引为当前行的索引,为解析下一个JSON对象做准备。
  8. 处理最后一个JSON对象: 循环结束后,最后一个JSON对象仍然在 lines 列表中,从 current_object_start_line 到列表末尾。因此,需要一个额外的步骤来解析它。

注意事项与总结

  1. 数据格式依赖性: 这种方法高度依赖于每个JSON对象以 } 结尾,并且下一个对象以 { 开始的特定模式。如果数据流中存在其他分隔符或更复杂的结构(例如,JSON对象内部的字符串也包含 { 或 } 但不在行首或行尾),则此方法可能需要调整或失效。
  2. 错误处理: 在实际应用中,应加入更健壮的错误处理机制。例如,如果 json.loads() 失败,应该捕获 json.JSONDecodeError 异常,并决定是跳过该片段、记录错误信息,还是终止解析过程。示例代码中已加入了基本的错误捕获。
  3. 性能考量: 对于非常大的数据流,逐行读取和字符串拼接可能会消耗较多的内存和CPU。如果性能是关键因素,可以考虑使用更流式(streaming)的解析器,或者在拼接字符串时优化内存使用。
  4. 数据清洗: 在 splitlines() 之前使用 strip() 是一个好习惯,可以去除整个数据流开头和结尾可能存在的无关空白字符。同样,在比较行内容时使用 line.strip() 可以忽略行内的前导/尾随空白。

通过上述基于行识别边界的策略,我们可以有效地解析和处理那些不符合标准JSON数组格式,而是以非标准方式直接连接的多个JSON对象流。这种方法为处理来自不规范数据源的JSON数据提供了一个实用的解决方案。

以上就是Python中解析非标准格式的多重JSON对象流的详细内容,更多请关注其它相关文章!


# js  # json  # app  # ai  # stream  # 数据清洗  # 格式化输出  # python  # 网络推广营销博主排名榜  # 谷歌seo速成  # 里水禅城网站建设  # 下拉关键词排名拣选mars10  # 绵阳建设专业网站  # 江门大型网站如何优化  # seo零基础入门教程  # 阳泉外贸网站推广厂家  # 大同商城网站建设好处  # 海曙网站推广哪家好点啊  # 移除  # 跳过  # 几种  # 中文网  # 遍历  # 浮点  # 第一个  # 是一个  # 多个  # 非标准  # json数组 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: 京东快递物流信息不更新怎么办_物流停滞原因与处理方法  iQOO手机信号差网络不稳定怎么办 信号问题原因排查与增强设置【攻略】  J*aScript深度克隆:实现高效、健壮与安全的复杂对象复制  手机坏了微信聊天记录怎么导出来 新手机恢复聊天记录技巧  Lar*el Eloquent:高效删除多对多关系中无关联子记录的父模型  在J*a中如何实现在线问答与评分系统_问答评分项目开发方法说明  猫眼电影app怎么查询电影院的营业时间_猫眼电影影院营业时间查询教程  苹果iPhone14ProMax如何新建AppleID_iPhone14ProMax新建AppleID具体流程  性能与资源监视器快捷打开  在Peewee中处理PostgreSQL记录重复:一站式数据摄取教程  POKI小游戏在线免费入口链接 POKI小游戏无下载秒玩玩  雨课堂官网在线登录 网页版雨课堂登录链接  windows10怎么更改下载路径_windows10默认存储位置修改教程  键盘保修需要什么_键盘售后维修流程  解决CSS布局中意外顶部空白问题的教程  FullCalendar自定义按钮样式定制指南  邦丰播放器频道搜索设置  告别阻塞等待:如何使用GuzzlePromises优雅处理PHP异步操作,提升应用响应速度  《密马》发布账号方法  银信通自动开通原因揭秘  一加 Ace 6V 快充无法启用_一加 Ace 6V 充电优化  PHP utf8_encode 字符编码转换疑难解析与最佳实践  宝妈做视频号该写什么标签话题?宝妈关注的话题有哪些?  毒蘑菇VOLUMESHADER_BM官网首页登录入口 毒蘑菇VOLUMESHADER_BM官网首页登录入口说明  iPhone14无法连接蓝牙设备如何解决  《下一站江湖2》武器获取方法  抖音火山版注销账号抖音会注销吗 抖音火山版与抖音账号注销关系  iPhone17Pro如何连接蓝牙耳机_iPhone17Pro蓝牙设备配对与连接方法介绍  实现可重用自定义Python Range类  Leaflet地图弹出窗口图片动态显示:避免缺失图标的专业指南  除了Copilot,还有哪些值得一试的VS Code AI插件?  《美篇》取消会员自动续费方法  J*aScript实现网页表单实时输入字段比较与验证教程  《星露谷物语》克林特好感度事件介绍  c++中的const关键字用法大全_c++ const正确使用指南  windows10怎么设置电源按钮_windows10按下电源键功能修改  TikTok视频播放不流畅怎么办 TikTok视频播放优化方法  在PySimpleGUI中实现键盘按键绑定按钮事件  小米倒班助手添加日历提醒  海棠阅读网页版_进入海棠网页版在线阅读中心  《图怪兽》退出登录方法  手机远程连接电脑方法  冬季去哪个城市旅游更有可能观测到极光  windows10怎么关闭自动安装应用_windows10禁止推广应用下载  word页码灰色不能用如何解决  iPhone16Plus参数配置如何调整声音_iPhone16Plus参数配置声音调整详细方法  PHP使用DOMDocument与XPath精准追加XML元素教程  163邮箱网页版官方登录入口 163邮箱网页版访问页面  163邮箱登录入口官网 163.com邮箱登录入口  《我的恋爱逃生攻略》中文名字输入方法 

 2025-12-06

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.