Skip to content

Commit 641230d

Browse files
committed
init
0 parents  commit 641230d

46 files changed

Lines changed: 18838 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
# 从零开始的 JSON 库教程 (Go语言版)
2+
3+
* 基于 Milo Yip 的 C语言JSON教程改编
4+
* 2025年
5+
6+
这是一个使用Go语言实现的JSON库教程,基于[《从零开始的 JSON 库教程》](https://github.com/miloyip/json-tutorial)改编。本教程保持原教程的章节结构和渐进式开发方法,但根据Go语言的特性进行了适当调整。
7+
8+
## 对象与目标
9+
10+
教程对象:学习过基本Go语言编程的同学。
11+
12+
通过这个教程,同学可以了解如何从零开始写一个Go语言版本的JSON库,其特性如下:
13+
14+
* 符合标准的JSON解析器和生成器
15+
* 使用Go语言的递归下降解析器(recursive descent parser)
16+
* 跨平台(如Windows/Linux/macOS)
17+
* 支持UTF-8 JSON文本
18+
* 使用Go语言内置类型存储JSON数据
19+
* 解析器和生成器的代码简洁高效
20+
* 提供丰富的访问和修改API
21+
22+
除了围绕JSON作为例子,希望能在教程中讲述一些课题:
23+
24+
* 测试驱动开发(test driven development, TDD)
25+
* Go语言编程风格
26+
* 数据结构
27+
* API设计
28+
* 错误处理
29+
* Unicode
30+
* 浮点数
31+
* Go模块、单元测试等工具和实践
32+
33+
## 项目结构
34+
35+
教程按照章节组织,每个章节对应一个子目录:
36+
37+
1. tutorial01: 基础结构、解析null/true/false
38+
2. tutorial02: 解析数字
39+
3. tutorial03: 解析字符串
40+
4. tutorial04: Unicode支持
41+
5. tutorial05: 解析数组
42+
6. tutorial06: 解析对象
43+
7. tutorial07: 生成器
44+
8. tutorial08: 访问与其他功能
45+
9. tutorial09: 增强的错误处理
46+
47+
## 当前进度
48+
49+
当前已经完成了所有教程的实现,包括:
50+
51+
* null、true、false等字面值
52+
* 数字(包括整数、浮点数、科学计数法)
53+
* 字符串(支持转义序列和Unicode)
54+
* 数组(支持嵌套)
55+
* 对象(支持嵌套)
56+
* JSON生成器 - 将JSON值转换为文本
57+
* 高级功能:
58+
* 对象键值查询
59+
* JSON值比较
60+
* 深度复制、移动和交换
61+
* 动态数组和对象操作
62+
* 高效内存管理
63+
* 增强错误处理:
64+
* 详细的错误信息与位置
65+
* 错误恢复能力
66+
* 自定义解析选项
67+
* 支持JSON注释
68+
69+
## 安装与使用
70+
71+
要使用这个库,你需要Go语言环境(推荐Go 1.16或更高版本)。克隆该仓库后,可以直接导入使用:
72+
73+
```go
74+
import "github.com/Cactusinhand/go-json-tutorial/tutorial08"
75+
// 或使用增强错误处理版本
76+
import "github.com/Cactusinhand/go-json-tutorial/tutorial09"
77+
78+
func main() {
79+
// 基本解析JSON
80+
v := leptjson.Value{}
81+
if err := leptjson.Parse(&v, `{"name": "John", "age": 30}`); err != leptjson.PARSE_OK {
82+
// 处理错误
83+
}
84+
85+
// 使用增强错误处理
86+
options := leptjson.ParseOptions{
87+
RecoverFromErrors: true, // 启用错误恢复
88+
AllowComments: true, // 允许JSON注释
89+
MaxDepth: 1000 // 设置最大嵌套深度
90+
}
91+
if err := leptjson.ParseWithOptions(&v, `{"name": "John", /* 这是注释 */ "age": 30}`, options); err != leptjson.PARSE_OK {
92+
// 错误处理但仍能继续解析
93+
fmt.Println("解析遇到错误但已恢复:", err)
94+
}
95+
96+
// 访问解析后的数据
97+
name := leptjson.GetString(leptjson.GetObjectValueByKey(&v, "name"))
98+
age := leptjson.GetNumber(leptjson.GetObjectValueByKey(&v, "age"))
99+
100+
// 使用FindObjectKey快速访问
101+
if value, found := leptjson.FindObjectKey(&v, "name"); found {
102+
name = leptjson.GetString(value)
103+
}
104+
105+
// 修改JSON数据
106+
newPerson := &leptjson.Value{}
107+
leptjson.SetObject(newPerson)
108+
nameValue := leptjson.SetObjectValue(newPerson, "name")
109+
leptjson.SetString(nameValue, "Alice")
110+
111+
// 动态数组操作
112+
arr := &leptjson.Value{}
113+
leptjson.SetArray(arr, 0)
114+
elem := leptjson.PushBackArrayElement(arr)
115+
leptjson.SetNumber(elem, 42)
116+
117+
// 生成JSON字符串
118+
jsonStr, _ := leptjson.Stringify(newPerson)
119+
}
120+
```
121+
122+
## 关键API说明
123+
124+
### 解析和生成
125+
* `Parse(&v, json)`: 解析JSON文本到Value结构
126+
* `ParseWithOptions(&v, json, options)`: 使用自定义选项解析JSON文本
127+
* `Stringify(&v)`: 将Value结构转换为JSON文本
128+
129+
### 类型和值访问
130+
* `GetType(&v)`: 获取JSON值的类型
131+
* `GetBoolean(&v)`, `SetBoolean(&v, b)`: 获取/设置布尔值
132+
* `GetNumber(&v)`, `SetNumber(&v, n)`: 获取/设置数字值
133+
* `GetString(&v)`, `SetString(&v, s)`: 获取/设置字符串值
134+
135+
### 数组操作
136+
* `GetArraySize(&v)`: 获取数组大小
137+
* `GetArrayElement(&v, index)`: 获取数组元素
138+
* `SetArray(&v, capacity)`: 设置为数组类型
139+
* `PushBackArrayElement(&v)`: 添加数组元素
140+
* `PopBackArrayElement(&v)`: 移除最后一个元素
141+
* `InsertArrayElement(&v, index)`: 插入元素
142+
* `EraseArrayElement(&v, index, count)`: 删除元素
143+
* `ClearArray(&v)`: 清空数组
144+
145+
### 对象操作
146+
* `GetObjectSize(&v)`: 获取对象大小
147+
* `GetObjectKey(&v, index)`: 获取对象键
148+
* `GetObjectValue(&v, index)`: 获取对象值
149+
* `GetObjectValueByKey(&v, key)`: 根据键获取对象值
150+
* `FindObjectKey(&v, key)`: 查找键并返回值
151+
* `SetObject(&v)`: 设置为对象类型
152+
* `SetObjectValue(&v, key)`: 设置对象键值
153+
* `RemoveObjectValue(&v, index)`: 移除成员
154+
* `ClearObject(&v)`: 清空对象
155+
156+
### 内存和资源管理
157+
* `Copy(dst, src)`: 深度复制JSON值
158+
* `Move(dst, src)`: 移动JSON值
159+
* `Swap(lhs, rhs)`: 交换两个JSON值
160+
* `Free(&v)`: 释放资源
161+
162+
### 比较和其他
163+
* `Equal(lhs, rhs)`: 比较两个JSON值是否相等
164+
165+
### 增强错误处理
166+
* `ParseOptions`: 定义解析选项的结构体,包含错误恢复、注释支持和最大深度等选项
167+
* `EnhancedError`: 提供详细的错误信息,包括行号、列号、上下文和错误位置指示
168+
* `GetErrorMessage(code)`: 获取特定错误码的错误描述信息
169+
170+
## 测试
171+
172+
每个章节都包含完整的测试用例,测试覆盖了各种正常和边缘情况。运行测试:
173+
174+
```bash
175+
go test ./tutorial08
176+
```
177+
178+
## 注意事项
179+
180+
* 处理Unicode时,需要特别注意UTF-16代理对的处理
181+
* 数字解析需要考虑各种边缘情况,如前导零、溢出等
182+
* 字符串解析需要正确处理所有转义序列
183+
* 数组和对象解析需要处理嵌套和边界情况
184+
* 在使用动态数组和对象函数时,注意内存管理和资源释放
185+
186+
## 参考资料
187+
188+
* [JSON官方规范](https://www.json.org/)
189+
* [原始C语言教程](https://github.com/miloyip/json-tutorial)
190+
* [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159)
191+
* [RFC 3629: UTF-8, a transformation format of ISO 10646](https://tools.ietf.org/html/rfc3629)

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/Cactusinhand/go-json-tutorial
2+
3+
go 1.16

plan.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
对于 JSON 库的未来计划和可能的扩展特性,我想提出以下几个方向:
2+
3+
## 未来计划与潜在新特性
4+
5+
1. **性能优化**
6+
- 使用更高效的内存分配策略,减少垃圾回收压力
7+
- 实现流式解析,处理超大 JSON 文件而不必一次性载入内存
8+
- 采用并发解析技术处理大型 JSON 数据
9+
10+
2. **功能扩展**
11+
- **JSON Path 支持**:实现类似 XPath 的查询语言,方便从复杂 JSON 结构中提取数据
12+
- **JSON Schema 验证**:支持根据 JSON Schema 验证 JSON 数据的结构和内容
13+
- **JSON Patch 操作**:实现 RFC 6902 的 JSON Patch 标准,支持增量修改
14+
- **JSON Merge Patch**:实现 RFC 7396 的 JSON Merge Patch 标准,提供更简单的更新方式
15+
16+
3. **错误处理增强**
17+
- 提供更详细的错误信息,包括行号、列号和上下文
18+
- 支持错误恢复,在某些错误情况下尝试继续解析
19+
20+
4. **工具与集成**
21+
- 提供命令行工具进行 JSON 格式化、验证和转换
22+
- 提供对其他数据格式的转换支持,如 YAML、TOML、XML 等
23+
- 与数据库序列化/反序列化集成
24+
- 支持 struct tag 映射,自动转换 Go 结构体与 JSON
25+
26+
5. **特殊需求支持**
27+
- 支持 JSON5 和 JSON Lines 等 JSON 扩展格式
28+
- 支持注释处理
29+
- 支持更大范围的数值类型,如大整数
30+
- 支持自定义格式化输出样式
31+
32+
6. **高级数据结构**
33+
- 实现 JSON 指针(JSON Pointer)
34+
- 支持循环引用检测和处理
35+
- 实现 JSON-LD (JSON for Linked Data) 支持
36+
37+
7. **文档与示例**
38+
- 编写更详细的使用文档和 API 参考
39+
- 提供更多实际应用场景的示例代码
40+
- 性能基准测试和与其他库的对比
41+
42+
8. **跨平台与兼容性**
43+
- 实现 WebAssembly 支持,使库可在浏览器环境中使用
44+
- 提供对较老 Go 版本的兼容性支持
45+
46+
9. **安全性增强**
47+
- 添加防止 DoS 攻击的机制(如递归深度限制、输入大小限制)
48+
- 提供安全的序列化/反序列化方法,防止数据注入攻击
49+
50+
10. **教学扩展**
51+
- 添加详细的算法解释和设计思想文档
52+
- 开发互动式教程,帮助理解 JSON 处理原理
53+
- 拓展到其他格式的解析器实现,如 YAML、XML 等
54+
55+
这些计划可以根据实际需求和用户反馈进行优先级排序。最重要的是保持库的简洁性和易用性,在添加新功能的同时不影响核心功能的性能和稳定性。未来的发展可以考虑将核心库保持简单,然后通过扩展模块提供高级功能。

prompt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
请以第一章和第二章第三章为最佳实践,请完成剩余的章节。
3+
一切按照第一第二第三章节的最佳实践进行,同时与原C项目的章节内容保持一一对应,各章节之间保持连贯,README文档也要保持如此,接口测试,单元测试,基准测试都不能少,
4+
只需要按照每个功能点,依据最佳测试实践原则,测试驱动原则,一一进行充分测试即可。
5+
6+
7+
我想与一位精通Go和C语言的JSON解析专家交谈,他是高效率的并发编程大师和接口设计师,深入理解内存管理和标准库。
8+
我正在开发一个JSON解析器的教学项目,同时包含C和Go两种实现,需要遵循测试驱动开发的最佳实践。
9+
希望这位专家能帮我设计清晰的API接口,实现高性能的JSON解析和生成功能,并编写全面的单元测试、基准测试和文档。
10+
请分享如何在保持两种语言实现一致性的同时,充分发挥各自语言特性的经验
11+
12+
13+
现在为了让我们的代码更加健壮,需要适当增加更多测试用例,请参照 tutorial06 中的实践,
14+
分别给tutorial01, tutorial02, tutorial03, tutorial04, tutorial05 增加更多 edge case, complex case,
15+
当然这些并不是必须的,你可以根据各个章节的实际内容进行分析,该需要补充测试用例的就补充,没必要补充的就不补充。

0 commit comments

Comments
 (0)