讲师中心 微信公众号
AI工具推荐 视频效率加速

如何在 Go 中检测 JSON 输入中的重复键

秋杰君_9117

秋杰君_9117

发布时间:2026-01-08 13:28:08

|

930人浏览过

|

来源于php中文网

原创

如何在 Go 中检测 JSON 输入中的重复键

go 标准库的 `encoding/json` 不支持重复键检测,但可通过基于事件的流式解析器(如 `garyburd/json`)实现:遍历 json 令牌时维护对象键哈希表栈,遇重复键立即返回错误。

在 Go 中,标准 encoding/json 包默认采用“后写覆盖”策略处理重复键——即同一对象中多次出现的相同键,仅保留最后一个值,且不报错、不告警。这与 Python 的 json.loads(object_hook=...) 可定制化行为不同,也不同于 Python 中通过 object_pairs_hook 实现有序字典或重复键拦截的能力。

要实现重复键检测并主动报错,核心思路是绕过完整结构反序列化,改用事件驱动(SAX-style)的流式解析器,逐个读取 JSON 令牌(token),并在解析过程中动态跟踪嵌套层级与当前对象的已见键集合。

推荐使用 github.com/garyburd/json(注意:该项目已归档,但代码稳定、轻量、无外部依赖,仍广泛用于需精细控制的场景)。它提供类似 bufio.Scanner 的接口,按需生成 json.Object、json.String、json.Number、json.Name 等事件,非常适合构建自定义验证逻辑。

以下是一个生产就绪的重复键检测函数示例:

Python Dependency Candidate Fetcher 2
Python Dependency Candidate Fetcher 2

根据包的能力以及 Jupyter 环境中的导入语句,从候选列表中挑选最适合用户表格工作流的 Python 包。

下载
package main

import (
    "fmt"
    "github.com/garyburd/json"
    "io"
    "strings"
)

type context struct {
    kind json.Kind
    keys map[string]struct{} // 使用空结构体节省内存
}

func ValidateDuplicateKeys(r io.Reader) error {
    scanner := json.NewScanner(r)
    var stack []context

    for scanner.Scan() {
        kind := scanner.Kind()

        switch kind {
        case json.Object, json.Array:
            // 进入新对象或数组,压入上下文
            stack = append(stack, context{
                kind: kind,
                keys: make(map[string]struct{}),
            })
        case json.End:
            // 遇到结束标记(} 或 ]),弹出栈顶
            if len(stack) == 0 {
                return fmt.Errorf("mismatched closing token: no matching start")
            }
            stack = stack[:len(stack)-1]
        case json.Name:
            // 仅当栈非空且顶层为对象时,才检查键名
            if len(stack) > 0 && stack[len(stack)-1].kind == json.Object {
                key := string(scanner.Name())
                if _, exists := stack[len(stack)-1].keys[key]; exists {
                    // 构造可读路径(可选增强)
                    path := buildJSONPath(stack)
                    return fmt.Errorf("duplicate key %q at path %s", key, path)
                }
                stack[len(stack)-1].keys[key] = struct{}{}
            }
        // 其他类型(string/number/bool/null)无需特殊处理
        }
    }

    if err := scanner.Err(); err != nil {
        return fmt.Errorf("parse error: %w", err)
    }

    if len(stack) != 0 {
        return fmt.Errorf("unclosed JSON structure: %d unclosed levels", len(stack))
    }

    return nil
}

// buildJSONPath 是一个辅助函数,用于生成类似 "root.y.z" 的路径提示(可选)
func buildJSONPath(stack []context) string {
    if len(stack) == 0 {
        return "root"
    }
    // 简化版:实际中可结合 Name() 和索引信息构建精确路径
    return "root" // 生产环境建议扩展为支持路径追踪
}

func main() {
    // 示例:含嵌套重复键的非法 JSON
    input := strings.NewReader(`
    {
        "x": 10,
        "y": {
            "z": 1,
            "z": 2   // ← 重复键
        },
        "z": [1,2,3]
    }`)

    if err := ValidateDuplicateKeys(input); err != nil {
        fmt.Printf("❌ Validation failed: %v\n", err) // 输出:duplicate key "z" at path root.y
    } else {
        fmt.Println("✅ Valid JSON: no duplicate keys found")
    }
}

✅ 关键设计说明:

  • 栈式上下文管理:每个 { 对应一个 context 入栈,记录该对象内已见键;} 出栈,确保嵌套对象独立校验;
  • 零分配键集:使用 map[string]struct{} 而非 map[string]bool,更省内存;
  • 错误定位友好:可轻松扩展 buildJSONPath 函数,结合 scanner.Name() 和栈深度生成结构化路径(如 "data.items.0.id");
  • 健壮性保障:显式检查 scanner.Err() 和未闭合结构,避免静默失败。

⚠️ 注意事项:

  • garyburd/json 已归档,不接受新特性,但其 API 稳定、无依赖、性能优异,适合嵌入式或高可靠性场景;
  • 若需长期维护或社区支持,可评估替代方案如 github.com/tidwall/gjson(只读)或 github.com/mitchellh/mapstructure(配合自定义解码器),但需自行实现事件循环;
  • 对于“保持原始顺序”的需求(即 Go 中的有序 map),标准 map 无序,可改用 []struct{Key, Value interface{}} 切片 + 自定义 UnmarshalJSON 方法,或直接使用 garyburd/json 扫描时按序收集键值对。

综上,Go 虽无内置 object_hook,但通过流式解析器+栈式状态机,不仅能精准捕获重复键,还可灵活支撑有序解析、路径追踪、部分解码等高级 JSON 处理场景。

热门AI工具

更多
豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

Flowith
Flowith Hot

Flowith是一款基于画布和智能体工作流的 AI 协作工作空间。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

小橡皮AI

一款AI工具,主要用于小橡皮一键去AI味,将机器味重的内容改得更有活人感,防止因为 AI 内容被平台打上 AI 标签,以及限流,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

花生AI
花生AI Hot

一款AI视频创作工具,主要用于B站推出的AI视频创作工具,适合需要提升相关任务效率的用户。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

2235

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

3582

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

1196

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

4139

2025.09.10

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

7019

2023.08.02

登录token无效
登录token无效

登录token无效解决方法:1、检查token的有效期限,如果token已经过期,需要重新获取一个新的token;2、检查token的签名,如果签名不正确,需要重新获取一个新的token;3、检查密钥的正确性,如果密钥不正确,需要重新获取一个新的token;4、使用HTTPS协议传输token,建议使用HTTPS协议进行传输 ;5、使用双因素认证,双因素认证可以提高账户的安全性。

14726

2023.09.14

登录token无效怎么办
登录token无效怎么办

登录token无效的解决办法有检查Token是否过期、检查Token是否正确、检查Token是否被篡改、检查Token是否与用户匹配、清除缓存或Cookie、检查网络连接和服务器状态、重新登录或请求新的Token、联系技术支持或开发人员等。本专题为大家提供token相关的文章、下载、课程内容,供大家免费下载体验。

1725

2023.09.14

token怎么获取
token怎么获取

获取token值的方法:1、小程序调用“wx.login()”获取 临时登录凭证code,并回传到开发者服务器;2、开发者服务器以code换取,用户唯一标识openid和会话密钥“session_key”。想了解更详细的内容,可以阅读本专题下面的文章。

4097

2023.12.21

Tailwind CSS 如何制作导航栏和卡片
Tailwind CSS 如何制作导航栏和卡片

用 Tailwind CSS 制作导航栏和卡片,可先搭建语义化结构,再组合 Flex、Grid、间距、圆角与阴影类。这里整理横向导航、移动端菜单、卡片网格及悬停效果的相关文章,帮助你把常见页面组件做得清晰且适配不同屏幕。

0

2026.11.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn