Json和Lua table互转的Lua模块

Json和Lua table互转的Lua模块

先分词,再解析,少写了语法检查

module( "json_to_lua", package.seeall )--##############################################################################--# 模块接口--##############################################################################-- json字符串转lua tablefunction JsonStrToLuaTable( szJsonStr )    local tWords = SplitWord( szJsonStr )    -- 此处应该加一个语法检查的    -- CheckSyntax( tWords )    local ResultObj = CreateObjectByWords( tWords )    return ResultObjend-- lua table转jsonfunction LuaTableToJsonStr( tTable, nTabCnt )    nTabCnt = nTabCnt or 0    local szJsonStr = ""    assert( type( tTable ) == "table", "tTable is not a table." )    local szTab = ""    for i = 1, nTabCnt do        szTab = szTab .. ''    end    local szKeyType = nil    for key, value in pairs( tTable ) do        if szKeyType == nil then            szKeyType = type( key )            if szKeyType ~= "string" and szKeyType ~= "number" then                -- 处理不了其他类型的key                return nil            end        end        -- 处理key,key类型不一致,转换失败        if type( key ) ~= szKeyType then            return nil        end        szJsonStr = szJsonStr .. '' .. szTab        if szKeyType == "string" then            szJsonStr = szJsonStr .. string.format( ""%s" = ", EscDecode( key ) )        end        -- 处理value        if type( value ) == "table" then            szJsonStr = szJsonStr .. LuaTableToJsonStr( value, nTabCnt + 1 ) .. ","        else            if type( value ) == 'string' then                value = '"' .. EscDecode( value ) .. '"'            end            szJsonStr = szJsonStr .. string.format( "%s,", value )        end    end    if szJsonStr == '' then szTab = ''; szJsonStr = '' end    if szKeyType == "string" then        return "{" .. szJsonStr .. szTab .. '}'    else        return "[" .. szJsonStr .. szTab .. ']'    endend-- 文件中读json文件并转成Lua tablefunction JsonFileToLuaTable( szJsonFileName )    local JsonFileObj = io.open( szJsonFileName, 'r' )    if JsonFileObj == nil then        return nil    end    local szJsonStr = JsonFileObj:read( "*a" )    io.close( JsonFileObj )    return JsonStrToLuaTable( szJsonStr )end-- Lua table生成json并保存到文件function LuaTableToJsonFile( tTable, szJsonFileName )    local JsonFileObj = io.open( szJsonFileName, 'w' )    szJsonStr = LuaTableToJsonStr( tTable )    if szJsonStr == nil then        return false    else         JsonFileObj:write(szJsonStr)        io.close( JsonFileObj )        return true    endend--##############################################################################--# 主要函数--##############################################################################tJson2Lua = {    ["true"] = { value = true },    ["null"] = { value = nil },    ["false"] = { value = false },}tStr2Esc = {    ["""] = '"', ["f"] = 'f', [""] = '', ["/"] = '/',    ["\"] = '', [""] = '', [""] = '', [""] = '',}tEsc2Str = {    ['"'] = """, ['f'] = "f", [''] = "", ['/'] = "/",    [''] = "", [''] = "", [''] = ""}-- 分词function SplitWord( szJsonStr )    local tWords = {}    if szJsonStr == nil then        return nil    end    szJsonStr = StringTrim( szJsonStr )    local nIndex = 1    while nIndex <= #szJsonStr do        repeat          -- breake实现continue            local szChar = szJsonStr:sub( nIndex, nIndex )            -- 跳过空白字符            if ( " " ):find( szChar, 1, true ) then                break            end            -- 处理语法的字符和字符串            if ( "{:}[,]"" ):find( szChar, 1, true ) then                tWords[#tWords + 1] = szChar                if szChar == '"' then                    local szTempStr = ""                    nIndex = nIndex + 1                    local szNextChar = szJsonStr:sub( nIndex, nIndex )                    while szNextChar ~= szChar do                        szTempStr = szTempStr .. szNextChar                        if szNextChar == '' and nIndex + 1 <= #szJsonStr then                            nIndex = nIndex + 1                            szTempStr = szTempStr .. szJsonStr:sub( nIndex, nIndex )                        end                        nIndex = nIndex + 1                        szNextChar = szJsonStr:sub( nIndex, nIndex )                    end                    tWords[#tWords + 1] = szTempStr                    tWords[#tWords + 1] = szChar                end            -- 处理数字            elseif CharIsDigit(szChar) or szChar == '-' or szChar == '.' then                local szNumStr = szChar                if szChar == '.' then szNumStr = '0.' end                while nIndex + 1 <= #szJsonStr do                    local szNextChar = szJsonStr:sub( nIndex + 1, nIndex + 1 )                    if ( "AaBbCcDdEeFfXx. -+" ):find( szNextChar, 1, true ) or                        CharIsDigit( szNextChar ) then                        if szNextChar ~= ' ' then                            szNumStr = szNumStr .. szNextChar                        end                        nIndex = nIndex + 1                    else break end                end                tWords[#tWords + 1] = szNumStr            elseif CharIsAlpha( szChar ) then                local szTempStr = szChar                while nIndex + 1 <= #szJsonStr do                    local szNextChar = szJsonStr:sub( nIndex + 1, nIndex + 1 )                    if CharIsAlpha( szNextChar ) then                        szTempStr = szTempStr .. szNextChar                        nIndex = nIndex + 1                    else break end                end                tWords[#tWords + 1] = szTempStr            end        until ( true )  -- breake实现continue        nIndex = nIndex + 1    end    return tWordsend-- 根据分词创建对象function CreateObjectByWords( tWords, tCur )    tCur = tCur or { 1 }    local nIndex = tCur[1]    -- 处理字典    if tWords[nIndex] == '{' then        local ResultObj = {}        nIndex = nIndex + 1        while nIndex <= #tWords do            if tWords[nIndex] == '}' then                tCur[1] = nIndex                return ResultObj            elseif tWords[nIndex] == '"' then                szKey = EscEncode( tWords[nIndex + 1] )                tCur[1] = nIndex + 4                ResultObj[szKey] = CreateObjectByWords( tWords, tCur )                nIndex = tCur[1]            end            nIndex = nIndex + 1        end    -- 处理数组    elseif tWords[nIndex] == '[' then        local ResultObj = {}        local nArrayLen = 0        nIndex = nIndex + 1        while nIndex <= #tWords do            if tWords[nIndex] == ']' then                tCur[1] = nIndex                return ResultObj            elseif tWords[nIndex] ~= ',' then                tCur[1] = nIndex                ResultObj[nArrayLen + 1] = CreateObjectByWords( tWords, tCur )                nArrayLen = nArrayLen + 1                nIndex = tCur[1]            end            nIndex = nIndex + 1        end    -- 处理字符串    elseif tWords[nIndex] == '"' then        tCur[1] = nIndex + 2        return EscEncode( tWords[nIndex + 1] )    -- 处理false, true, null    elseif tJson2Lua[tWords[nIndex]] ~= nil then        return tJson2Lua[tWords[nIndex]].value    elseif tWords[nIndex] ~= ',' then        return tonumber( tWords[nIndex] )    endend-- 处理转义字符function EscEncode( szString )    for str, esc in pairs( tStr2Esc ) do        szString = string.gsub( szString, str, esc)    end    return szStringendfunction EscDecode( szString )    szString = string.gsub( szString, '', "\")    for esc, str in pairs( tEsc2Str ) do        szString = string.gsub( szString, esc, str)    end    return szStringend-- 打印lua tablefunction PrintTable( tTable, szContext, nTabCnt )    nTabCnt = nTabCnt or 0    szContext = szContext or ""    assert( type( tTable ) == "table", "tTable is not a table." )    local szTab = ""    for i = 1, nTabCnt do        szTab = szTab .. ''    end    print( szContext .. '{' )    for key, value in pairs( tTable ) do        if type( key ) == 'string' then            key = '"' .. EscDecode( key ) .. '"'        end        local szTemp = '' .. szTab .. string.format( "[%s] = ", key )        if type( value ) == "table" then            PrintTable( value, szTemp, nTabCnt + 1)        else            if type( value ) == 'string' then                value = '"' .. EscDecode( value ) .. '"'            end            print( szTemp .. string.format( "%s,", value ) )        end    end    print( szTab .. '}' )end--##############################################################################--# 字符串辅助函数--##############################################################################-- 删除前后空白字符function StringTrim( szString )    if type( szString ) ~= "string" then        return ""    end    return ( string.gsub( string.gsub( szString, "%s+$", "" ), "^%s+", "" ) )end-- 判断是数字function CharIsDigit( szChar )    assert( #szChar == 1, "szChar is not a char: " .. szChar )    return ( '0' ):byte() <= szChar:byte() and szChar:byte() <= ( '9' ):byte()end-- 判断是字母function CharIsAlpha( szChar )    assert( #szChar == 1, "szChar is not a char: " .. szChar )    return ( ( 'a' ):byte() <= szChar:byte() and szChar:byte() <= ( 'z' ):byte() ) or            ( ( 'A' ):byte() <= szChar:byte() and szChar:byte() <= ( 'Z' ):byte() )end

测试用例:

{    "root": [ "JSON Test Pattern pass1", { "object with 1 member": [ "array with 1 element" ] }, {}, [], -42, true, false, null, { "integer": 1234567890, "real": -9876.54321, "e": 1.23456789e-13, "E": 1.23456789e+34, "zero": 0, "one": 1, "space": " ", "quote": """, "backslash": "", "slash": "/ & /", "alpha": "abcdefghijklmnopqrstuvwyz", "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", "digit": "0123456789" }, 0.5, 98.6, 99.44, 1066, "rosebud" ] }

推荐阅读