package main import ( "fmt" "strings" "github.com/buger/jsonparser" ) func main() { fmt.Println("=== 从不完整 JSON 中提取字段值的示例 ===") fmt.Println() // 测试案例 1: 不完整的字符串值 fmt.Println("1. 提取不完整的字符串值:") incompleteJSON1 := `{"name": "Alice", "info": "hello world this is incomplete` if value, found := ExtractIncompleteValue(incompleteJSON1, "info"); found { fmt.Printf(" 提取到的值: %s\n", value) } else { fmt.Println(" 未找到该字段") } // 测试案例 2: 完整的字符串后面还有不完整的字段 fmt.Println("\n2. 提取完整字段和不完整字段:") incompleteJSON2 := `{"status": "ok", "data": "complete data", "partial": "incomp` if value, found := ExtractIncompleteValue(incompleteJSON2, "status"); found { fmt.Printf(" status: %s (完整)\n", value) } if value, found := ExtractIncompleteValue(incompleteJSON2, "data"); found { fmt.Printf(" data: %s (完整)\n", value) } if value, found := ExtractIncompleteValue(incompleteJSON2, "partial"); found { fmt.Printf(" partial: %s (不完整)\n", value) } // 测试案例 3: 处理转义字符 fmt.Println("\n3. 处理带转义的不完整字符串:") incompleteJSON3 := `{"text": "hello \"world\" this is \n incomplete` if value, found := ExtractIncompleteValue(incompleteJSON3, "text"); found { fmt.Printf(" 提取到的值: %s\n", value) } // 测试案例 4: 数字和布尔值(不完整) fmt.Println("\n4. 提取不完整的数字值:") incompleteJSON4 := `{"count": 12345, "price": 99.` if value, found := ExtractIncompleteValue(incompleteJSON4, "count"); found { fmt.Printf(" count: %s (完整)\n", value) } if value, found := ExtractIncompleteValue(incompleteJSON4, "price"); found { fmt.Printf(" price: %s (不完整)\n", value) } // 测试案例 5: 嵌套对象(部分不完整) fmt.Println("\n5. 提取嵌套字段:") incompleteJSON5 := `{"user": {"name": "Bob", "email": "bob@exam` if value, found := ExtractNestedValue(incompleteJSON5, "user", "name"); found { fmt.Printf(" user.name: %s (完整)\n", value) } if value, found := ExtractNestedValue(incompleteJSON5, "user", "email"); found { fmt.Printf(" user.email: %s (不完整)\n", value) } // 测试案例 6: 实际流式场景模拟 fmt.Println("\n6. 模拟流式接收数据:") streamChunks := []string{ `{"id": 1, "message": "`, `这是一段很长的消息内容`, `,正在逐步接收中...`, `","timestamp": 16`, } accumulated := "" for i, chunk := range streamChunks { accumulated += chunk fmt.Printf(" 收到第 %d 块数据: %s\n", i+1, chunk) if value, found := ExtractIncompleteValue(accumulated, "message"); found { fmt.Printf(" -> 当前 message 值: %s\n", value) } } fmt.Println("\n=== 使用方法总结 ===") fmt.Println("jsonparser 无法处理不完整的 JSON,") fmt.Println("所以我们需要手动实现字符串解析来提取不完整字段。") fmt.Println("上面的 ExtractIncompleteValue 函数可以:") fmt.Println(" - 从不完整的 JSON 中提取指定 key 的值") fmt.Println(" - 处理字符串、数字、布尔值等类型") fmt.Println(" - 处理转义字符") fmt.Println(" - 即使值不完整也能返回已接收到的部分") } // ExtractIncompleteValue 从不完整的 JSON 中提取指定 key 的值(即使值不完整) func ExtractIncompleteValue(jsonData, targetKey string) (string, bool) { // 查找目标 key(带引号) keyPattern := fmt.Sprintf(`"%s"`, targetKey) keyIndex := strings.Index(jsonData, keyPattern) if keyIndex == -1 { return "", false } // 找到 key 后面的冒号 colonIndex := strings.Index(jsonData[keyIndex:], ":") if colonIndex == -1 { return "", false } // 跳过冒号和空白字符 startIndex := keyIndex + colonIndex + 1 for startIndex < len(jsonData) && isWhitespace(jsonData[startIndex]) { startIndex++ } if startIndex >= len(jsonData) { return "", false } // 判断值的类型并提取 switch jsonData[startIndex] { case '"': // 字符串类型 return extractStringValue(jsonData[startIndex+1:]), true case '{': // 对象类型 return extractUntilMatchingBrace(jsonData[startIndex:]), true case '[': // 数组类型 return extractUntilMatchingBracket(jsonData[startIndex:]), true default: // 数字、布尔值、null return extractPrimitiveValue(jsonData[startIndex:]), true } } // ExtractNestedValue 提取嵌套字段(支持一层嵌套) func ExtractNestedValue(jsonData string, parentKey, childKey string) (string, bool) { // 先找到父对象 parentPattern := fmt.Sprintf(`"%s"`, parentKey) parentIndex := strings.Index(jsonData, parentPattern) if parentIndex == -1 { return "", false } // 找到父对象的开始位置 colonIndex := strings.Index(jsonData[parentIndex:], ":") if colonIndex == -1 { return "", false } startIndex := parentIndex + colonIndex + 1 for startIndex < len(jsonData) && isWhitespace(jsonData[startIndex]) { startIndex++ } if startIndex >= len(jsonData) || jsonData[startIndex] != '{' { return "", false } // 在父对象内查找子字段 return ExtractIncompleteValue(jsonData[startIndex:], childKey) } // extractStringValue 提取字符串值(处理转义,支持不完整) func extractStringValue(data string) string { var result strings.Builder escaped := false for i := 0; i < len(data); i++ { ch := data[i] if escaped { result.WriteByte(ch) escaped = false continue } if ch == '\\' { escaped = true result.WriteByte(ch) continue } if ch == '"' { // 遇到未转义的引号,字符串结束 break } result.WriteByte(ch) } return result.String() } // extractPrimitiveValue 提取原始值(数字、布尔、null) func extractPrimitiveValue(data string) string { var result strings.Builder for i := 0; i < len(data); i++ { ch := data[i] // 遇到这些字符表示值结束 if ch == ',' || ch == '}' || ch == ']' || ch == '\n' || ch == '\r' { break } if !isWhitespace(ch) { result.WriteByte(ch) } else if result.Len() > 0 { // 如果已经开始收集内容,遇到空白字符就停止 break } } return result.String() } // extractUntilMatchingBrace 提取到匹配的 } 为止 func extractUntilMatchingBrace(data string) string { level := 0 for i := 0; i < len(data); i++ { switch data[i] { case '{': level++ case '}': level-- if level == 0 { return data[:i+1] } } } return data // 返回全部(不完整) } // extractUntilMatchingBracket 提取到匹配的 ] 为止 func extractUntilMatchingBracket(data string) string { level := 0 for i := 0; i < len(data); i++ { switch data[i] { case '[': level++ case ']': level-- if level == 0 { return data[:i+1] } } } return data // 返回全部(不完整) } // isWhitespace 判断是否为空白字符 func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' } func sample() { // 示例 JSON 数据 data := []byte(`{ "person": { "name": { "first": "张", "last": "三" }, "age": 30, "github": "https://github.com/zhangsan", "email": "zhangsan@example.com" }, "company": "Example Corp", "skills": ["Go", "Python", "JavaScript"], "scores": [85, 92, 78, 95], "active": true, "balance": 1234.56, "metadata": null, "tags": { "level": "senior", "department": "engineering" } }`) fmt.Println("=== buger/jsonparser API 示例 ===") fmt.Println() // 1. Get() - 获取字符串值(返回 value, dataType, offset, err) fmt.Println("1. Get() - 获取简单值") if value, dataType, _, err := jsonparser.Get(data, "company"); err == nil { fmt.Printf(" company: %s (类型: %s)\n", string(value), dataType) } // 2. 获取嵌套对象的值 fmt.Println("\n2. Get() - 获取嵌套对象的值") if firstName, _, _, err := jsonparser.Get(data, "person", "name", "first"); err == nil { fmt.Printf(" first name: %s\n", string(firstName)) } if lastName, _, _, err := jsonparser.Get(data, "person", "name", "last"); err == nil { fmt.Printf(" last name: %s\n", string(lastName)) } // 3. GetInt() - 获取整数值 fmt.Println("\n3. GetInt() - 获取整数值") if age, err := jsonparser.GetInt(data, "person", "age"); err == nil { fmt.Printf(" age: %d 岁\n", age) } // 4. GetFloat() - 获取浮点数值 fmt.Println("\n4. GetFloat() - 获取浮点数值") if balance, err := jsonparser.GetFloat(data, "balance"); err == nil { fmt.Printf(" balance: ¥%.2f\n", balance) } // 5. GetBoolean() - 获取布尔值 fmt.Println("\n5. GetBoolean() - 获取布尔值") if active, err := jsonparser.GetBoolean(data, "active"); err == nil { fmt.Printf(" active: %t\n", active) } // 6. ArrayEach() - 遍历字符串数组 fmt.Println("\n6. ArrayEach() - 遍历数组") fmt.Print(" skills: ") jsonparser.ArrayEach(data, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { fmt.Printf("%s ", string(value)) }, "skills") fmt.Println() // 7. 遍历数字数组并计算总和 fmt.Println("\n7. ArrayEach() - 处理数字数组") var total int64 var count int jsonparser.ArrayEach(data, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { if num, err := jsonparser.ParseInt(value); err == nil { total += num count++ fmt.Printf(" [%d] = %d\n", count-1, num) } }, "scores") if count > 0 { fmt.Printf(" 统计: 总和=%d, 平均分=%.2f\n", total, float64(total)/float64(count)) } // 8. GetUnsafeString() - 获取字符串(零拷贝,性能最好) fmt.Println("\n8. GetUnsafeString() - 高性能字符串获取(零拷贝)") if github, err := jsonparser.GetUnsafeString(data, "person", "github"); err == nil { fmt.Printf(" github: %s\n", github) } fmt.Println(" 注意: GetUnsafeString 返回的字符串指向原始 JSON 数据,不会分配新内存") // 9. ObjectEach() - 遍历对象的所有键值对 fmt.Println("\n9. ObjectEach() - 遍历对象") fmt.Println(" person.name 的所有字段:") jsonparser.ObjectEach(data, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error { fmt.Printf(" %s: %s (类型: %s)\n", string(key), string(value), dataType) return nil }, "person", "name") // 10. Set() - 设置/修改值 fmt.Println("\n10. Set() - 修改 JSON 值") newData, err := jsonparser.Set(data, []byte(`"Example Tech Inc."`), "company") if err == nil { if company, _, _, err2 := jsonparser.Get(newData, "company"); err2 == nil { fmt.Printf(" 修改后的 company: %s\n", string(company)) } } // 11. Delete() - 删除键 fmt.Println("\n11. Delete() - 删除键") newData = jsonparser.Delete(data, "metadata") fmt.Println(" 已删除 metadata 字段") // 验证删除 if _, _, _, err := jsonparser.Get(newData, "metadata"); err != nil { fmt.Printf(" 验证: metadata 已不存在 (%v)\n", err) } // 12. GetString() - 直接获取字符串(会分配新内存) fmt.Println("\n12. GetString() - 获取字符串值") if company, err := jsonparser.GetString(data, "company"); err == nil { fmt.Printf(" company: %s\n", company) } if email, err := jsonparser.GetString(data, "person", "email"); err == nil { fmt.Printf(" email: %s\n", email) } // 13. EachKey() - 批量获取多个键(高性能,只遍历一次 JSON) fmt.Println("\n13. EachKey() - 批量获取多个键(一次遍历)") paths := [][]string{ {"company"}, {"person", "age"}, {"active"}, {"balance"}, } jsonparser.EachKey(data, func(idx int, value []byte, vt jsonparser.ValueType, err error) { switch idx { case 0: fmt.Printf(" company: %s\n", string(value)) case 1: fmt.Printf(" age: %s\n", string(value)) case 2: fmt.Printf(" active: %s\n", string(value)) case 3: fmt.Printf(" balance: %s\n", string(value)) } }, paths...) fmt.Println(" 注意: EachKey 比多次调用 Get 更高效") // 14. 数据类型检查 - Get 返回 4 个值 fmt.Println("\n14. Get() 返回值详解") value, dataType, offset, err := jsonparser.Get(data, "person", "age") if err == nil { fmt.Printf(" 值: %s\n", string(value)) fmt.Printf(" 类型: %s\n", dataType) fmt.Printf(" 偏移量: %d\n", offset) fmt.Println(" 注意: Get 返回 (value []byte, dataType ValueType, offset int, err error)") } // 15. 处理数组中的对象 fmt.Println("\n15. 处理复杂的嵌套结构") complexData := []byte(`{ "users": [ {"id": 1, "name": "Alice", "role": "admin"}, {"id": 2, "name": "Bob", "role": "user"}, {"id": 3, "name": "Charlie", "role": "user"} ] }`) fmt.Println(" users:") jsonparser.ArrayEach(complexData, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { id, _ := jsonparser.GetInt(value, "id") name, _ := jsonparser.GetString(value, "name") role, _ := jsonparser.GetString(value, "role") fmt.Printf(" ID: %d, Name: %-8s, Role: %s\n", id, name, role) }, "users") // 16. 错误处理示例 fmt.Println("\n16. 错误处理") if _, _, _, err := jsonparser.Get(data, "nonexistent"); err != nil { fmt.Printf(" 尝试获取不存在的键: %v\n", err) } // 17. 处理 null 值 fmt.Println("\n17. 处理 null 值") if _, dataType, _, err := jsonparser.Get(data, "metadata"); err == nil { if dataType == jsonparser.Null { fmt.Printf(" metadata 是 null 值 (类型: %s)\n", dataType) } } // 18. ObjectEach 遍历整个对象 fmt.Println("\n18. ObjectEach() - 遍历 tags 对象的所有字段") jsonparser.ObjectEach(data, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error { fmt.Printf(" %s: %s\n", string(key), string(value)) return nil }, "tags") // 19. 使用 ParseInt 和 ParseFloat fmt.Println("\n19. ParseInt/ParseFloat - 解析字节数组") ageBytes, _, _, _ := jsonparser.Get(data, "person", "age") if ageInt, err := jsonparser.ParseInt(ageBytes); err == nil { fmt.Printf(" ParseInt: age = %d\n", ageInt) } balanceBytes, _, _, _ := jsonparser.Get(data, "balance") if balanceFloat, err := jsonparser.ParseFloat(balanceBytes); err == nil { fmt.Printf(" ParseFloat: balance = %.2f\n", balanceFloat) } // 20. 判断数据类型 fmt.Println("\n20. ValueType - 所有数据类型") checkType(data, "person", "name", "first") // String checkType(data, "person", "age") // Number checkType(data, "active") // Boolean checkType(data, "metadata") // Null checkType(data, "skills") // Array checkType(data, "person") // Object fmt.Println("\n=== 示例完成 ===") fmt.Println("\n性能提示:") fmt.Println(" - GetUnsafeString: 零拷贝,最快,但返回的字符串生命周期与原始数据相同") fmt.Println(" - GetString: 分配新内存,安全,但稍慢") fmt.Println(" - EachKey: 批量获取多个键时,只遍历一次 JSON,比多次 Get 快") fmt.Println(" - ArrayEach/ObjectEach: 流式处理,内存占用小") } // checkType 辅助函数:检查并打印数据类型 func checkType(data []byte, keys ...string) { if _, dataType, _, err := jsonparser.Get(data, keys...); err == nil { path := keys[0] for i := 1; i < len(keys); i++ { path += "." + keys[i] } var typeName string switch dataType { case jsonparser.String: typeName = "String (字符串)" case jsonparser.Number: typeName = "Number (数字)" case jsonparser.Object: typeName = "Object (对象)" case jsonparser.Array: typeName = "Array (数组)" case jsonparser.Boolean: typeName = "Boolean (布尔)" case jsonparser.Null: typeName = "Null (空值)" case jsonparser.Unknown: typeName = "Unknown (未知)" default: typeName = "NotExist (不存在)" } fmt.Printf(" %s -> %s\n", path, typeName) } }