JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,广泛应用于前后端数据交互,服务器消息推送、移动应用程序数据存储等场景。在Lua中,我们使用json库对JSON进行解析与序列化。json库是由RapidJSON C++ 库改写的的C语言实现的json解析库,可以在Lua与C/C++之间无缝兼容,极大地方便了在Lua环境下的JSON解析与序列化操作。
一、JSON基础知识
JSON是一种轻量级的数据交换格式,在语法上与JavaScript中的对象字面量非常相似,这方便了Javascript中的JSON解析,同时也给了其他编程语言更广泛的JSON解析工具。在JSON中,数据对象包含在一个花括号内,用逗号分隔。 在其中属性-值对被称为JSON对象,其中属性用双引号括起来,值可以是字符串、数字、逻辑值、数组或嵌套的JSON对象。 例如:
{
"name": "Alice",
"age": 23,
"gender": "female",
"contacts": {
"email": "alice@test.com",
"phone": "1234567890"
},
"hobbies": ["reading", "swimming", "travel"]
}
二、使用Lua解析JSON
在Lua中,我们可以使用json库对JSON进行解析,json库是由RapidJSON C++ 库改写的C语言实现的JSON解析库,支持UTF-8编码。 在使用时,我们需要将json库导入到我们的代码中,例如:
local json = require "json"
然后使用`json.decode()`函数进行JSON字符串的解析,例如:
local str = '{"name":"Alice","age":23,"gender":"female","contacts":{"email":"alice@test.com","phone":"1234567890"},"hobbies":["reading","swimming","travel"]}'
local data = json.decode(str)
则最终`data`的值为一个Lua对象,包含了JSON数据中的所有信息。
三、使用Lua对JSON进行序列化
除了解析JSON,我们还可以使用json库将Lua对象序列化为JSON字符串。使用`json.encode()`函数进行序列化,例如:
local data = {
name = "Alice",
age = 23,
gender = "female",
contacts = {
email = "alice@test.com",
phone = "1234567890"
},
hobbies = {"reading", "swimming", "travel"}
}
local str = json.encode(data)
则最终`str`的值为一个JSON字符串,与之前的JSON数据格式一致。
四、使用Lua编写自己的JSON解析器
除了使用json库解析JSON,我们也可以自己编写一个简单的JSON解析器,了解JSON的解析原理和实现方式。 在编写JSON解析器时,我们可以将JSON数据看作一个树形的数据结构,在解析的过程中,逐步地构建这个树形结构,最终形成一个Lua对象。 例如:
local json = require "json"
-- 解析JSON字符串
local function parse(jsonStr)
local pos = 1 -- 当前解析到的位置
local len = string.len(jsonStr) -- JSON字符串的总长度
-- 解析一个值
local function parseValue()
local ch = string.sub(jsonStr, pos, pos)
if ch == "{" then -- 解析JSON对象
local obj = {}
pos = pos + 1
ch = string.sub(jsonStr, pos, pos)
while ch ~= "}" do
if ch == '"' then -- 解析属性名
pos = pos + 1
local key = parseString()
pos = pos + 1 -- 跳过":"符号
obj[key] = parseValue() -- 递归解析属性值
ch = string.sub(jsonStr, pos, pos)
elseif ch == "," then -- 分隔符
pos = pos + 1
ch = string.sub(jsonStr, pos, pos)
else
error("unexpected char: " .. ch)
end
end
pos = pos + 1
return obj
elseif ch == "[" then -- 解析JSON数组
local arr = {}
pos = pos + 1
ch = string.sub(jsonStr, pos, pos)
local i = 1
while ch ~= "]" do
arr[i] = parseValue()
i = i + 1
ch = string.sub(jsonStr, pos, pos)
end
pos = pos + 1
return arr
elseif ch == '"' then -- 解析JSON字符串
return parseString()
elseif ch == "t" then -- 解析JSON布尔值true
pos = pos + 4
return true
elseif ch == "f" then -- 解析JSON布尔值false
pos = pos + 5
return false
elseif ch == "n" then -- 解析JSON空值null
pos = pos + 4
return nil
else -- 解析JSON数字
return parseNumber()
end
end
-- 解析JSON字符串
local function parseString()
local start = pos + 1
local find = string.find(jsonStr, '"', start)
local endpos = find
while true do
if find == nil then
error("miss double quote")
end
if string.sub(jsonStr, find-1, find-1) == "\\" then
endpos = string.find(jsonStr, '"', endpos+1)
else
break
end
end
pos = endpos
return json.decode(string.sub(jsonStr, start, endpos))
end
-- 解析JSON数字
local function parseNumber()
local startpos = pos
while true do
local ch = string.sub(jsonStr, pos, pos)
if ch >= "0" and ch <= "9" or ch == "+" or ch == "-" or
ch == "e" or ch == "E" or ch == "." then
pos = pos + 1
else
break
end
end
local endpos = pos - 1
return tonumber(string.sub(jsonStr, startpos, endpos))
end
-- 解析JSON字符串
return parseValue()
end
local str = '{"name":"Alice","age":23,"gender":"female","contacts":{"email":"alice@test.com","phone":"1234567890"},"hobbies":["reading","swimming","travel"]}'
local data = parse(str)
通过自己编写JSON解析器的方式,我们可以更深度地理解JSON的解析原理,同时也能够更好地掌握Lua的语法特性和函数使用方法。
五、总结
JSON是一种简单、轻量级的数据交换格式,在前后端数据交互中有着广泛的应用。在Lua中,我们可以使用json库对JSON进行解析和序列化,也可以通过编写自己的JSON解析器,更深入地理解JSON的解析原理和Lua语法特性。无论使用何种方式,掌握好JSON的解析和序列化操作都是成为一名优秀的Lua工程师必须掌握的技能之一。