Files
playground/stream_message/main.go
mouseleee 4716b82f29 commit
2025-11-05 03:35:37 +08:00

509 lines
16 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}
}