leptjson

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 16, 2025 License: MIT Imports: 4 Imported by: 0

README

从零开始的 JSON 库教程(三):解析字符串 (Go语言版)

1. JSON 字符串语法

JSON 的字符串语法和 Go 语言很相似,都是以双引号把字符括起来,如 "Hello"。但字符串采用了双引号作分隔,那么怎样可以在字符串中插入一个双引号? 把 a"b 写成 "a"b" 肯定不行,都不知道那里是字符串的结束了。因此,我们需要引入转义字符(escape character),Go 语言和 JSON 都使用 \(反斜线)作为转义字符,那么 " 在字符串中就表示为 \"a"b 的 JSON 字符串则写成 "a\"b"。如以下的字符串语法所示,JSON 共支持 9 种转义序列:

string = quotation-mark *char quotation-mark
char = unescaped /
   escape (
       %x22 /          ; "    quotation mark  U+0022
       %x5C /          ; \    reverse solidus U+005C
       %x2F /          ; /    solidus         U+002F
       %x62 /          ; b    backspace       U+0008
       %x66 /          ; f    form feed       U+000C
       %x6E /          ; n    line feed       U+000A
       %x72 /          ; r    carriage return U+000D
       %x74 /          ; t    tab             U+0009
       %x75 4HEXDIG )  ; uXXXX                U+XXXX
escape = %x5C          ; \
quotation-mark = %x22  ; "
unescaped = %x20-21 / %x23-5B / %x5D-10FFFF

简单翻译一下,JSON 字符串是由前后两个双引号夹着零至多个字符。字符分为无转义字符或转义序列。转义序列有 9 种,都是以反斜线开始,如常见的 \n 代表换行符。比较特殊的是 \uXXXX,当中 XXXX 为 16 进位的 UTF-16 编码,本单元将不处理这种转义序列,留待下回分解。

无转义字符就是普通的字符,语法中列出了合法的码点范围(码点还是在下单元才介绍)。要注意的是,该范围不包括 0 至 31、双引号和反斜线,这些码点都必须要使用转义方式表示。

2. 字符串表示

在 Go 语言中,字符串是一种基本类型,表示为不可变的字节序列。Go 字符串可以包含任何字节,包括空字节('\0')。这与 C 语言中的空结尾字符串(null-terminated string)不同,C 语言中以空字符代表字符串的结束。

例如,JSON 字符串 "Hello\u0000World" 在解析后是一个包含 11 个字符的字符串,其中包含一个空字符。在 Go 中,我们可以直接使用内置的 string 类型来表示这样的字符串,而不需要像 C 语言那样特殊处理空字符。

在我们的 JSON 库中,我们将使用 Go 的 string 类型来存储解析后的字符串值。

3. 内存管理

与 C 语言不同,Go 语言有自动内存管理(垃圾回收),我们不需要手动分配和释放内存。当我们创建一个字符串时,Go 运行时会自动处理内存分配,当字符串不再被引用时,垃圾回收器会自动回收内存。

在我们的 JSON 库中,当设置一个值为字符串时,我们只需要简单地将字符串赋值给 Value 结构体中的相应字段:

func (v *Value) SetString(s string) {
    v.Type = STRING
    v.S = s
}

4. 解析字符串

解析 JSON 字符串需要处理转义序列。我们需要检查字符串是否以双引号开始和结束,然后解析字符串内容,处理各种转义序列。

在本章中,我们将实现字符串的解析功能,包括处理各种转义序列,如 \"\\\/\b\f\n\r\t。我们暂时不处理 Unicode 转义序列 \uXXXX,这将在下一章中实现。

5. 总结

本章我们将实现 JSON 字符串的解析,包括:

  1. 修改 Value 结构体,添加字符串类型的支持
  2. 实现字符串的解析函数
  3. 处理各种转义序列
  4. 添加相应的单元测试

通过本章的学习,我们的 JSON 库将能够解析 JSON 字符串,为后续解析更复杂的 JSON 数据类型(如数组和对象)打下基础。

Documentation

Overview

leptjson.go - Go语言版JSON库实现

这个包实现了一个简单的JSON解析器,支持基本的JSON值类型 包括null、true、false、数字和字符串等。后续版本将支持数组和对象。

字符串解析的特殊情况处理: 1. 基本规则:

  • 字符串必须以双引号开始和结束
  • 单引号是非法的
  • 字符串中的双引号必须转义
  • 空字符串""是合法的

2. 转义序列:

  • 标准转义序列:\"、\\、\/、\b、\f、\n、\r、\t
  • 其他转义序列都是非法的(如\v、\a等)
  • 转义序列必须完整(如"\n"是合法的,但"\n"后面跟着其他字符是非法的)

3. Unicode处理:

  • 支持\uXXXX格式的Unicode转义
  • 支持UTF-16代理对(\uD800-\uDFFF)
  • 代理对必须成对出现(高代理项后必须跟低代理项)
  • 单独的低代理项是非法的

4. 控制字符处理:

  • 所有小于0x20的控制字符必须转义
  • 未转义的控制字符是非法的

5. 字符串长度限制:

  • 理论上没有长度限制
  • 但实际实现中可能受限于内存大小

6. 错误处理:

  • PARSE_MISS_QUOTATION_MARK: 缺少右引号
  • PARSE_INVALID_STRING_ESCAPE: 无效的转义序列
  • PARSE_INVALID_STRING_CHAR: 无效的字符
  • PARSE_INVALID_UNICODE_HEX: 无效的Unicode十六进制
  • PARSE_INVALID_UNICODE_SURROGATE: 无效的Unicode代理对

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetNumber

func GetNumber(v *Value) float64

GetNumber 获取JSON数字值

当且仅当值类型为NUMBER时,返回值有效

func GetString

func GetString(v *Value) string

GetString 获取JSON字符串值

当且仅当值类型为STRING时,返回值有效

func GetStringLength

func GetStringLength(v *Value) int

GetStringLength 获取JSON字符串长度

当且仅当值类型为STRING时,返回值有效

func SetString

func SetString(v *Value, s string)

SetString 设置JSON值为字符串

Types

type ParseError

type ParseError int

ParseError 表示解析过程中可能出现的错误

const (
	PARSE_OK                        ParseError = iota // 解析成功
	PARSE_EXPECT_VALUE                                // 期望一个值
	PARSE_INVALID_VALUE                               // 无效的值
	PARSE_ROOT_NOT_SINGULAR                           // 根节点不唯一
	PARSE_NUMBER_TOO_BIG                              // 数字太大
	PARSE_MISS_QUOTATION_MARK                         // 缺少引号
	PARSE_INVALID_STRING_ESCAPE                       // 无效的转义序列
	PARSE_INVALID_STRING_CHAR                         // 无效的字符
	PARSE_INVALID_UNICODE_HEX                         // 无效的 Unicode 十六进制数字
	PARSE_INVALID_UNICODE_SURROGATE                   // 无效的 Unicode 代理对
)

解析错误常量

func Parse

func Parse(v *Value, json string) ParseError

Parse 解析JSON文本

接收一个Value指针和JSON字符串,解析JSON并将结果存储在Value中 返回解析过程中可能出现的错误

func (ParseError) Error

func (e ParseError) Error() string

Error 实现error接口,返回错误描述

func (ParseError) String

func (e ParseError) String() string

type Value

type Value struct {
	Type ValueType `json:"type"` // 值类型
	N    float64   `json:"n"`    // 数字值(当Type为NUMBER时有效)
	S    string    `json:"s"`    // 字符串值(当Type为STRING时有效)
}

Value 表示一个JSON值

func (*Value) String

func (v *Value) String() string

String 实现fmt.Stringer接口,返回Value的字符串表示

type ValueType

type ValueType int

ValueType 表示JSON值的类型

const (
	NULL   ValueType = iota // null值
	FALSE                   // false值
	TRUE                    // true值
	NUMBER                  // 数字
	STRING                  // 字符串
	ARRAY                   // 数组
	OBJECT                  // 对象
)

JSON值类型常量

func GetType

func GetType(v *Value) ValueType

GetType 获取JSON值的类型

func (ValueType) String

func (t ValueType) String() string

String 返回ValueType的字符串表示

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL