Lua 实现JSON解析器
JSON
- JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
- JSON 是轻量级的文本数据交换格式
- JSON 独立于语言:JSON 使用 Javascript语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。 目前非常多的动态(PHP,JSP,.NET)编程语言都支持JSON。
- JSON 具有自我描述性,更易理解
JSON的组成
JSON 数据的书写格式是:
key : value
JSON 值可以是:
- 数字(整数或浮点数)
- 字符串(在双引号中)
- 逻辑值(true 或 false)
- 数组(在中括号中)
- 对象(在大括号中)
- null
JSON 解析器实现原理
JSON 解析器从本质上来说就是根据 JSON 文法规则创建的状态机
输入是一个 JSON 字符串,输出是一个Table。
状态机具体如下图所示:
具体代码实现
JsonLoader = {}
i = 1
json = ''
function JsonLoader:getChar(str, i)
--print(str, i)
return string.sub(str, i, i)
end
-- 跳过空格、换行、制表符、回车
function JsonLoader:skipWhitespace()
while (JsonLoader:getChar(json, i) == ' '
or JsonLoader:getChar(json, i) == '\n'
or JsonLoader:getChar(json, i) == '\t'
or JsonLoader:getChar(json, i) == '\r') do
i = i + 1
end
end
-- 处理逗号
function JsonLoader:eatComma()
if (JsonLoader:getChar(json, i) ~= ',') then
print('Expected ,')
end
i = i + 1
end
-- 处理冒号
function JsonLoader:eatColon()
if (JsonLoader:getChar(json, i) ~= ':') then
print('Expected :')
end
i = i + 1
end
-- 是否为16进制数
function JsonLoader:isHexadecimal(char)
return (char >= '0' and char <= '9') or (string.lower(char) >= 'a' and string.lower(char) <= 'f')
end
-- 获取字符串
function JsonLoader:parseString()
--print('parse String: ', i , 'times')
if (JsonLoader:getChar(json, i) == '"') then
i = i + 1
local result = ""
while (JsonLoader:getChar(json, i) ~= '"') do
if (JsonLoader:getChar(json, i) == '\\') then
char = JsonLoader:getChar(json, i+1)
if ( char == '"'
or char == '\\'
or char == '/'
or char == 'b'
or char == 'f'
or char == 'n'
or char == 'r'
or char == 't') then
result = result..char
i = i + 1
elseif (char == 'u') then
if (isHexadecimal(getChar(json, i+2))
and isHexadecimal(JsonLoader:getChar(json, i+3))
and isHexadecimal(JsonLoader:getChar(json, i+4))
and isHexadecimal(JsonLoader:getChar(json, i+5))) then
result = result .. string.sub(json,i+2, i+5)
i = i + 5
end
end
else
result = result .. JsonLoader:getChar(json, i)
-- 如果字符串为数字,进行转换
if tonumber(result) ~= nil then
result = tonumber(result)
end
end
i = i + 1
end
i = i + 1
--print("parse String res: ", result)
return result
end
return nil
end
-- 解析数值
function JsonLoader:parseNumber()
--print('parse Number: ', i , 'times')
start = i
if JsonLoader:getChar(json, i) == '-' then
i = i + 1
end
-- 解析数字,跳过首位0
if (JsonLoader:getChar(json, i) == '0') then
i = i +1
elseif (JsonLoader:getChar(json, i) >= '1' and JsonLoader:getChar(json, i) <= '9') then
i = i + 1
while(JsonLoader:getChar(json, i) >= '0' and JsonLoader:getChar(json, i) <= '9') do
i = i + 1
end
end
-- 检测小数
if(JsonLoader:getChar(json, i) == '.') then
i = i + 1
while(JsonLoader:getChar(json, i) >= '0' and JsonLoader:getChar(json, i) <= '9') do
i = i + 1
end
end
-- 检测科学计数法
if(JsonLoader:getChar(json, i) == 'e' or JsonLoader:getChar(json, i) == 'E') then
i = i + 1
if(JsonLoader:getChar(json, i) == '-' or JsonLoader:getChar(json, i) == '+') then
i = i + 1
end
while(JsonLoader:getChar(json, i) >= '0' and JsonLoader:getChar(json, i) <= '9') do
i = i + 1
end
end
if (i > start) then
--print('parse Number res: ', tonumber(string.sub(json, start, i-1)))
return tonumber(string.sub(json, start, i-1))
end
return nil
end
-- 解析关键字
function JsonLoader:parseKeyword(name, value)
if (string.sub(json, i, i + #name) == name) then
i = i + #name
return value
end
end
-- 解析对象
function JsonLoader:parseObject()
--print('parse Object: ', i , 'times')
if (JsonLoader:getChar(json, i)== '{') then
i = i + 1
JsonLoader:skipWhitespace()
local result = {}
initial = true
while (JsonLoader:getChar(json, i) ~= '}') do
if (not initial) then
JsonLoader:eatComma()
JsonLoader:skipWhitespace()
end
local key = JsonLoader:parseString()
JsonLoader:skipWhitespace()
JsonLoader:eatColon()
local value = JsonLoader:parseValue()
--print(key, value)
result[key] = value
initial = false
JsonLoader:skipWhitespace()
end
-- move to the next character of '}'
i = i + 1
--for k, v in pairs(result) do
-- print('202', k , v)
--
--end
--print('parse Object res: ', result)
return result
end
end
-- 解析值 递归调用其他方法
function JsonLoader:parseValue()
--print('parse Value: ', i , 'times')
JsonLoader:skipWhitespace()
local value
local string = JsonLoader:parseString()
local number = JsonLoader:parseNumber()
local object = JsonLoader:parseObject()
local array = JsonLoader:parseArray()
local tr = JsonLoader:parseKeyword('true', true)
local fl = JsonLoader:parseKeyword('false', false)
local ni = JsonLoader:parseKeyword('null', nil)
if string ~= nil then
return string
elseif number ~= nil then
return number
elseif object ~= nil then
return object
elseif array ~= nil then
return array
elseif tr == true then
return tr
elseif fl == false then
return fl
elseif ni == nil then
return ni
end
--local value = JsonLoader:parseString() or JsonLoader:parseNumber()
-- or JsonLoader:parseObject() or JsonLoader:parseKeyword('true', true)
-- or JsonLoader:parseKeyword('false', false) or JsonLoader:parseKeyword('null', nil)
JsonLoader:skipWhitespace()
--print('parse Value res:', value)
return value
end
-- 解析数组
function JsonLoader:parseArray()
--print('parse Array: ', i , 'times')
if (JsonLoader:getChar(json, i) == '[') then
i = i + 1
JsonLoader:skipWhitespace()
local result = {}
initial = true
while (JsonLoader:getChar(json, i) ~= ']') do
if (not initial) then
JsonLoader:eatComma()
end
local value = JsonLoader:parseValue()
table.insert(result, value)
initial = false
end
i = i + 1
return result
end
return nil
end
-- 解析主函数
function JsonLoader:parse(input_file)
print('start json parse')
--res = {}
--print(input_file)
-- 读取文件
local file = io.open(input_file, 'r')
json = file:read('*a')
file:close()
print(json)
-- json parse
--print(JsonLoader:getChar(json, i))
-- 判断首字符是否为'{'
if (JsonLoader:getChar(json, i) == '{') then
i = i + 1
JsonLoader:skipWhitespace()
-- 保存结果
local result = {}
initial = true
while (JsonLoader:getChar(json, i) ~= '}')
do
if not initial then
JsonLoader:eatComma()
JsonLoader:skipWhitespace()
end
local key = JsonLoader:parseString()
JsonLoader:skipWhitespace()
JsonLoader:eatColon()
local value = JsonLoader:parseValue()
--print("parse key- value: ",key, value)
result[key] = value
--print("273 res:", result[key])
JsonLoader:skipWhitespace()
initial = false
end
-- move to the next character '{'
i = i + 1
return result
end
return nil
end
input_file = 'a.json'
local mytable = JsonLoader.parse(nil, input_file)
print(' ---------------JsonLoader res -------------')
print(type(mytable))
print(mytable[1].a)
--[[
a.json
{"1":{"a":100}}
output:
table
100
]]--
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)