This commit is contained in:
mouseleee
2025-11-05 03:35:37 +08:00
parent 9e158bf9a3
commit 4716b82f29
3 changed files with 515 additions and 0 deletions

5
go.mod Normal file
View File

@@ -0,0 +1,5 @@
module git.goalfyagent.ai/lixuan/playground
go 1.25.3
require github.com/buger/jsonparser v1.1.1

2
go.sum Normal file
View File

@@ -0,0 +1,2 @@
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=

508
stream_message/main.go Normal file
View File

@@ -0,0 +1,508 @@
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)
}
}