這幾天草草的瀏覽了一下電子版的《lua程序設計》,沒有懂的地方就自動忽略了,挑揀了一些可以理解的部分一直在推進。推進至后面的時候已經渾渾噩噩的了,有種想看完這本書的強迫症的感覺。推進CAPI部分的時候發現難度一下子提升了,有種難以理解的感覺,而且這本書沒有相對應的練習,只是看書沒有進行相應的實踐,確實難度比較大。這里先暫緩推進這本書的進程,決定拿一下小的項目來試試寫lua代碼的感覺,寫完這個項目在回去體會lua程序設計這本書,這樣可能效果會更好一些。這里我會列出項目描述,而且會記錄完成這個項目的過程,當然,項目是一個非常簡單,而且已經存在優秀的開源庫的東西,但是這里先檢查一下自己是否能夠完成,完成之后可以參閱一下相關開源庫的實現,對比之中應該會有所提高。
項目描述:
基於lua 5.2.3 封裝實現一個可供其他lua腳本使用的功能模塊,具體要求為: 1、實現一個標准的lua功能模塊 2、封裝json格式的數據與lua value間的互相轉換功能 3、遵循json格式定義確保相同的數據源彼此轉換后數據仍然一致 4、只允許使用lua內建基礎庫,不允許使用任何第三方開發庫 5、有合理的注釋和單元測試代碼 6、獨立完成此作業,對任何代碼抄襲現象零容忍 基本要求: 提交lua代碼文件名為json.lua,測試代碼和文檔(如果有)可以打一個包作為第二個附件提交 json.lua中需要實現以下接口: function Marshal(json_str) return lua_val end function Unmarshal(lua_val) return "json_str" end 對基本要求的說明: 1、lua版本要求5.2.3 2、lua的空table統一轉化成json的空object,而不是空array 3、test case中的json_str符合ECMA-404 json格式標准 4、Unmarshal傳入的lua_val如果是table的話,不會有循環嵌套 5、table如果是以array方式使用,轉換如下:{[2]=1,[4]=1} == {nil,1,nil,1} <-> [null,1,null,1] 6、table中有string key時,統一處理成hash table的格式,如:{1,2;a=3} -> {"1":1,"2":2","a":3} 7、不會出現類似 {1,2;["2"]="same key 2 in json"} 造成轉換有歧義的table 8、Unicode轉成lua字符串時,按lua的字符串格式 \xXX\xYY... 9、能成功轉換的話,只需要return單個值 進階要求: 對test case的錯誤進行檢查,返回相應錯誤 function Marshal(json_str) return nil, "error_type" end 基本測試方法: local json = require 'json' local test_result1 = json.Marshal('{"a":1}') local test_result2 = json.Unmarshal{ b="cd" } -- validate test_result1 & test_result2
項目解決過程:
一.模塊
首先這個問題是實現一個模塊,在lua 5.1版開始,lua已經為模塊和包定義了一系列的規則,我們需要使用table,函數,元表和環境來實現這些規則。其中lua提供了兩個重要的函數實現這些規則,分別是require(使用模塊函數)和module(創建模塊函數)。
require可以加載模塊,這里加載到的為一個table,table內容包含該模塊提供的接口和成員變量;規則還定義一個規范的模塊應該可以使require返回該模塊的table。require使用方法為:
require "<模塊名>"。其實這里require的功能感覺和dofile比較像,但是還是存在區別的,require詳細的內容我目前也不是很理解,這里先略去。
完成了加載模塊的解釋,接下來就是自己實現模塊需要遵守什么樣的規則呢?模塊的主要功能就是定義一個table,然后定義這個table需要導出的成員接口&成員變量,然后返回這個table即完成了這個模塊的實現。module函數完成了很多簡化模塊編寫的功能;module函數的更加詳細部分以及模塊編寫的公共部分演化這里略去。
local modname = ... local M = {} _G[modname] = M package.loaded[modname] = M <setup for external access> setfenv(1,M)
關於子模塊和包的部分這里也利用不到,所以這部分知識也略去,關於lua程序設計一書中這部分講述也稍有復雜,其中印刷題中關於'-'和'_'區分不好,看起來比較吃力,不過關於require和module的部分講解的非常不錯。
所以這部分的代碼實現如下:
module(...,package.seeall) function Marshal(json_str) print(json_str) end function Unmarshal(lua_content) print(lua_content) end
這里把函數的內容簡化為只進行參數的輸出,后面繼續分析並實現函數的功能。
這部分看起來非常的容易,不過還是要明白其中的道理。
二.JSON語法簡析
json的語法非常的簡單,數據在 名稱/值 對中,數據由逗號分隔,花括號保存對象,方括號保存數組;
json的值類型包含:數字(整數或者浮點數),字符串(雙引號),邏輯值(true或者false),數組(方括號中),對象(花括號中),null
所以json語言還是比較簡單的。
談到這種解析的工作,之前接觸過(瀏覽過)一個自己實現的HTMLParser實現,使用的方法是自動機的策略進行實現的。這種有解析思路的項目均可以利用自動機的思想來實現,自動機的課程很早之前學習的了,此時發現智商好低,學習的內容基本都已經完全還給老師了。不過針對JSON的解析可以使用自動機的思路。這里我搬運一下json官網上的自動機圖解。
首先json數據是由對象 or 數組組成的基本結構;
json的對象由大括號包含的key:value組成,key:value之間由逗號隔開,其中key為string的類型,string類型具體定義下面給出。value的具體類型下面給出;
json的數組由中括號包含的value組成,value之間由逗號隔開,其中value的具體類型下面給出;
value的具體類型由string,number,object,array和一些其他json常量組成;
string是由雙引號包含的一個字符串,其中包含unicode編碼和一些轉義字符,其中unicode字符在lua中的存儲應該也是一個比較棘手的問題;
json中的轉義字符也是一個很bug的問題,lua字符串中也存在轉義字符。
而且lua中字符串的表示可以利用單引號,雙引號和雙中括號,其中單雙引號的功能比較類似,存在轉義符號。然而雙中括號會忽略轉義符號,所以這個地方編寫程序的時候應該特別注意。
所以lua中定義的json字符串的轉義符號要轉換為lua中的轉義字符串,根據上面自動機的標示有8個轉義字符和一個unicode轉義字符。lua的json字符串中的符號應該為"\\",\\/,\\\\,\\b,\\f,\\n,\\r,\\t,\\u...."這些了,分別應該轉為lua中的"",/,\,\b,\f,\n,\r,\t"。
當然lua中內部的轉義字符轉換也應該逆轉換過來;
所以會有兩個dict進行轉換; 關於unicode碼的轉換后面進行解釋;
json_to_lua = { ['\\"] = '"', ['\\/'] = '/', ['\\\\'] = '\\' ["\\t"] = "\t", ["\\f"] = "\f", ["\\r"] = "\r", ["\\n"] = "\n", ["\\b"] = "\b" } lua_json = { ['"'] = '\\"', ['\\'] = '\\\\', ['/'] = '\\/', ['\b'] = '\\b', ['\f'] = '\\f', ['\n'] = '\\n', ['\r'] = '\\r', ['\t'] = '\\t' }
數字的自動機轉移圖,其中數字包含正負類型,浮點數,整型,科學技術法,所以合法的數字類型的狀態機比較復雜,但是lua中有一個可以偷懶的地方在於tonumber函數的使用,可以將string轉換為number,如果轉換不合法,則返回nil;
三.lua編寫狀態機的一些知識
由於上面已經提及了自動機來實現json的解析,然而根據lua程序設計,函數尾調用一節中得知,在lua中”尾調用“的一大應用就是編寫”狀態機“。
”這種程序通常一個函數就是一個狀態,改變狀態利用’goto‘或尾調用到另外一個特定的函數。尾調用就是一個函數的return的最后語句是另外一個函數,此時針對此函數的棧信息不進行保存,所以最后一個函數調用相當於goto語句的調用,所以如此可以進行無限的調用也不會產生棧溢出的錯誤。尾調用詳細信息這里略去,只是簡單介紹一下。
另外lua中的字符串遍歷不是很方便,lua中的string是不變量,也沒有提供下標訪問的接口,所以只能利用string提供的sub函數去一個字符一個字符的遍歷;
四.具體代碼的實現
(1)json字符串的解析部分
a. Marsha1解析json字符串的接口,從第一個個字符開始遍歷json字符串,position設置為1。
b. skipBlank函數跳過空格,tab,換行等空白字符;
c. 找到第一個有效字符,‘{’或者‘[’,分別繼續調用decodeObject和decodeArray函數返回相應的內部lua table即可。如果不是這兩個符號,則此json字符串存在格式錯誤。
--two interface encode json or decode json function M.Marshal(json_str) local nowTime = os.time() --json must be json array or object local position = 1 position = M.skipBlank(json_str,position) --null json string case local json_len = string.len(json_str) if position > json_len then return nil,[[null json string]] end --change to json object or json array --otherwise,invalid local c = string.sub(json_str,position,position) local res if c == [[{]] then res = M.decodeObject(json_str,position) elseif c == [[[]] then res = M.decodeArray(json_str,position) else res = nil,[[error that json no an object or array,invalid]] end M.MarshalTime = M.MarshalTime + os.time() - nowTime return res end
接下來就是decodeObject,decodeArray,decodeNumber,decodeString,decodeOther等,分別對應於json中的object,array,number,string,true,false,null等變量;和skipBlank函數同樣,這些函數具有類似的輸入和輸出參數;
關於這些函數的輸入,因為整個過程是遍歷字符串,所以字符串和當前遍歷的位置信息比較重要,所以這些函數的傳入參數為json字符串和當前字符的位置信息;
這些函數的輸出函數分別為解析到的lua內部的數據結構和下一個字符的位置信息;
(這里實現的時候同樣可以把json字符串和指針的位置信息設置為兩個全局變量,思路相同)
了解完這些函數的思想之后接下來就容易理解這些函數的實現代碼。
跳過空白字符
其中在代碼debug的時候遇到了
malformed pattern (missing ']'),error的錯誤,
這里因為string.find函數把第二個參數中的'['符號判斷為正則表達式符號了,所以這里就產生錯誤,所以這里針對'['符號進行一下特殊處理;
其他方面就只檢測當前字符是不是自定義的blankcharacter中的一個即可
--skip the blank character --blank character include space,\n \r \t --params --[in] json_str : json string --[in] position : current position of the string --[out] the next of end position of the blank character function skipBlank(json_str,position) local blankcharacter = ' \t\r\n' local json_len = string.len(json_str) while position <= json_len do local c = string.sub(json_str,position,position) --malformed pattern (missing ']'),error if c == "[" then return position elseif string.find(blankcharacter,c) then position = position + 1 else break end end return position end
解析json object
函數看似比較復雜,其實邏輯比較清晰;
json object開始於 '{',結束於 '}',由key:value對組成,由 ',' 分隔;
不斷的讀取key , ':' , value 然后填入相應的lua table,返回lua table即可;
其中利用計數的方法保證 ',' 的語法正確;
--decode from json object --begin with '{' --params --[in] json_str : json string --[in] position : current position of the string --[out] lua table , the next of end the end position of the string function decodeObject(json_str,position) local lua_object = {} local key,subobject,subarray,str,number,othervalue local c = string.sub(json_str,position,position) --check case if c ~= [[{]] then base.print [[error that object not start with { ]] return nil,[[error in decodeObject begin]] end position = position + 1 position = skipBlank(json_str,position) c = string.sub(json_str,position,position) if c == [[}]] then position = position + 1 return lua_object,position end --then json array including {key:value,key:value,key:value,...} --key --> string --value including --string --number --object --array --true,false,nil ---------------------------------------------------------------- local precount = -1 local curcount = 0 local json_len = string.len(json_str) while position <= json_len do position = skipBlank(json_str,position) c = string.sub(json_str,position,position) --key:value if c == [[}]] then --object over if precount >= curcount then --,is adjace to ] base.print "error that , is adjace to }" return nil,"error that , is adjace to }" end break elseif c == [[,]] then --next key:value or over position = position + 1 precount = precount + 1 if 0 == curcount then --,is the first,error base.print [[error that , in key:value is the first]] return nil,[[error that , in key:value is the first]] end if precount >= curcount then --,is more than one base.print [[error that , in key:value is more than one]] return nil,[[error that , in key:value is more than one]] end elseif c == [["]] then --begin key:value key,position = decodeString(json_str,position) --: position = skipBlank(json_str,position) c = string.sub(json_str,position,position) if c ~= [[:]] then base.print [[error,that object not key:value format]] return nil,[[error in decodeObject,format error]] else position = position + 1 end --begin value position = skipBlank(json_str,position) c = string.sub(json_str,position,position) if c == '[' then subarray,position = decodeArray(json_str,position) lua_object[key] = subarray elseif c == '{' then subobject,position = decodeObject(json_str,position) lua_object[key] = subobject elseif c == [["]] then str,position = decodeString(json_str,position) lua_object[key] = str elseif string.find([[+-0123456789.e]],c) then number,position = decodeNumber(json_str,position) lua_object[key] = number else othervalue,position = decodeOther(json_str,position) if othervalue then lua_object[key] = othervalue end end if not lua_object[key] then base.print [[error in json object key:value --> value,can't get value]] return nil,[[error in decodeObject value]] else curcount = curcount + 1 end --end value else base.print [[error json format]] return nil,[[error json format,in decodeObject end]] end end return lua_object,position + 1 end
解析json array
json array的解析開始於 '[' 符號,結束於 ']' 符號,value值之間利用 ',' 隔開;
創建一個lua table,針對value值利用 t[#t+1] = value插入新的值,新的值根據符號調用相應的decode方法即可,
其中為了確保json語法錯誤被檢測出來,利用計數的方法保證 ',' 語法的正確;
--decode from json array --begin with '[' --params --[in] json_str : json string --[in] position : current position of the string --[out] lua table , the next of end the end position of the string function decodeArray(json_str,position) local lua_array = {} local c = string.sub(json_str,position,position) --check case if c ~= [[[]] then base.print [[error that array not start with [ ]] return nil,[[error in decodeArray begin]] end position = position + 1 position = skipBlank(json_str,position) c = string.sub(json_str,position,position) if c == ']' then position = position + 1 return lua_array,position end --then json array including [value,value,value...] --value including --string --number --object --array --true,false,nil ------------------------------------------------------------------------- --about [,] or ["hello",] or [,"hello"] or ["hello",,"world"] check error --using pre count & cur count to find this local precount = -1 local curcount = 0 local json_len = string.len(json_str) while position <= json_len do position = skipBlank(json_str,position) c = string.sub(json_str,position,position) if c == '[' then subarray,position = decodeArray(json_str,position) lua_array[#lua_array+1] = subarray curcount = curcount + 1 elseif c == '{' then subobject,position = decodeObject(json_str,position) lua_array[#lua_array+1] = subobject curcount = curcount + 1 elseif c == [["]] then str,position = decodeString(json_str,position) lua_array[#lua_array+1] = str curcount = curcount + 1 elseif string.find([[+-0123456789.e]],c) then number,position = decodeNumber(json_str,position) lua_array[#lua_array+1] = number curcount = curcount + 1 elseif c == ']' then --there is some bugs,which is end with , if precount >= curcount then --,is adjace to ] base.print "error that , is adjace to ]" return nil,"error that , is adjace to ]" end break elseif c == ',' then --there is some bugs,which is begin with , position = position + 1 precount = precount + 1 if 0 == curcount then --,is the first,error base.print [[error that , is the first]] return nil,[[error that , is the first]] end if precount >= curcount then --,is more than one base.print [[error that , is more than one]] return nil,[[error that , is more than one]] end else othervalue,position = decodeOther(json_str,position) lua_array[#lua_array+1] = othervalue curcount = curcount + 1 end end if position > json_len then base.print 'error that array not end with ]' return nil,[[error in decodeArray end]] end c = string.sub(json_str,position,position) if c ~= ']' then base.print 'error that array not end with ]' return nil,[[error in decodeArray end]] end position = position + 1 return lua_array,position end
解析json string
關於unicode的部分還未實現,還不是很了解這方面的知識;
關於string的解析僅僅是從第一個雙引號開始,找到最后一個雙引號且不是[[\"]],及轉義的雙引號,然后截取兩個雙引號之間的內容,得到字符串即可;
--decode json string,include json key of key/value and the string value --begin with ' " ' --params --[in] json_str : json string --[in] position : current position of the string --[out] lua string , the next of end the end position of the string function M.decodeString(json_str,position) nowTime = os.time() local endposition = position + 1 local json_len = string.len(json_str) while endposition <= json_len and ( [["]] ~= string.sub(json_str,endposition,endposition) or [[\]] == string.sub(json_str,endposition - 1,endposition - 1) ) do endposition = endposition + 1 end local str = string.sub(json_str,position + 1,endposition - 1) --process str str = string.gsub(str,'\\u....',function (tstr) local a = string.sub(tstr,3,6) local n = tonumber(a,16) local x if n < 0x80 then x = string.char(n % 0x80) elseif n < 0x800 then -- [110x xxxx] [10xx xxxx] x = string.char(0xC0 + (math.floor(n/64) % 0x20), 0x80 + (n % 0x40)) else -- [1110 xxxx] [10xx xxxx] [10xx xxxx] x = string.char(0xE0 + (math.floor(n/4096) % 0x10), 0x80 + (math.floor(n/64) % 0x40), 0x80 + (n % 0x40)) end return x end ) str = string.gsub(str,'\\.',escapeSequences) return str,endposition + 1 end
當然這其中有些轉義字符的處理,均利用string.gsub函數,針對相應字符如果table中包含,則進行替換,相關table和函數如下。
local ecapses = { ['"'] = '\\"', ['\\'] = '\\\\', ['/'] = '\\/', ['\b'] = '\\b', ['\f'] = '\\f', ['\n'] = '\\n', ['\r'] = '\\r', ['\t'] = '\\t' } function encodeString(s) return string.gsub(s,'.',function(c) return ecapses[c] end) end local escapeSequences = { ["\\t"] = "\t", ["\\f"] = "\f", ["\\r"] = "\r", ["\\n"] = "\n", ["\\b"] = "\b" } setmetatable(escapeSequences, {__index = function(t,k) -- skip "\" aka strip escape return string.sub(k,2) end})
解析json number
這里實現number的解析也比較偷懶,獲取到連續的比較像number的字符串,利用lua提供的tonumber函數轉換為number,失敗返回nil
--decode json number --the valid number of json,include float,int and so on --[in] json_str : json string --[in] position : current position of the string --[out] lua number , the next of end the end position of the string function decodeNumber(json_str,position) --string to number,lua have this function - tonumber local acceptCharacter = [[+-0123456789.e]] if not string.find(acceptCharacter,string.sub(json_str,position,position)) then base.print [[error that string not start with " ]] return nil,[[error in decodeNumber begin]] end --find the endposition local endposition = position local json_len = string.len(json_str) while endposition <= json_len and string.find(acceptCharacter,string.sub(json_str,endposition,endposition)) do endposition = endposition + 1 end local number = base.tonumber(string.sub(json_str,position,endposition - 1)) if not number then base.print [[error in number format]] return nil,[[error in decodeNumber end]] end return number,endposition end
解析json的一些常量
關於json中的常量包含true,false和null,解析得到相應的值即可;
--decode other json value --include boolean value(true,false) or null --[in] json_str : json string --[in] position : current position of the string --[out] lua boolean or nil , the next of end the end position of the string function decodeOther(json_str,position) --true,false,null, --three value -- "true" --> true -- "false"--> false -- "null" --> nil OtherString = {"true","false","null"} JsonLua = { ["true"] = true,["false"] = false,["null"] = nil } for i = 1,#OtherString do local str = OtherString[i] if string.sub(json_str,position,position + string.len(str) - 1) == str then return JsonLua[str],position + string.len(str) end end base.print [[error,invalid json other,not true,false,null]] return nil,[[error in decodeOther end]] end
(2)lua內部對象轉換json
這部分比較簡單,也存在一種可能是我考慮的比較簡單,目前感覺實現還是正確的,因為我在debug上面的時候實現了一個printLua函數,打印json轉換為lua table的內部結構;
打印出的結構剛好比較類似json的結構,所以后面只需要針對這個函數進行修改,輸出部分改為輸出至string即可
關於printLua函數:
這個函數的一個輔助函數是判斷lua中的table是否為數組形式,或者是鍵值對的形式;
--this function check lua_table is array or is an object --compare to json --if there exists one key/value in the lua_table,it's an object,otherwise,it's an array --[in] lua_table : table type in lua --[out] boolean and maxnumber of array : true indicate that the lua table is an array,false indicate that the lua table is an key/value table function LuaArray(lua_table) --if lua_table is an array,it imply that all its key's type is number --if lua_table is an key/value table,imply that there exists string type in its keys --so just check all its key type local isarray = true local maxindex = 0 for k,_ in base.pairs(lua_table) do if base.type(k) ~= [[number]] then isarray = false break elseif base.type(k) == [[number]] and (math.floor(k) ~= k or k < 1) then isarray = false break else maxindex = math.max(maxindex,k) end end return isarray,maxindex end --for test lua Table --output lua table --format output table function printLuaTable(luaT,space) local ss = string.rep([[ ]],space) local isarray,alen = LuaArray(luaT) if isarray then io.write(ss .. '[\n') for i = 1,alen do io.write(ss .. [[ ]]) if base.type(luaT[i]) == "boolean" then if luaT[i] then io.write('true\n') else io.write('false\n') end elseif base.type(luaT[i]) == "number" then io.write(luaT[i] .. '\n') elseif base.type(luaT[i]) == "string" then io.write(luaT[i] .. '\n') elseif base.type(luaT[i]) == "nil" then io.write('nil\n') else printLuaTable(luaT[i],space + 4) end end io.write(ss .. ']\n') else io.write(ss .. '{\n') for k,v in base.pairs(luaT) do local str = [[ ]] .. k .. ':' io.write(ss .. str) if base.type(v) == "boolean" then if v then io.write('true\n') else io.write('false\n') end elseif base.type(v) == "number" then io.write(v .. '\n') elseif base.type(v) == "string" then io.write(v .. '\n') else printLuaTable(v,space + 4) end end end io.write(ss .. '}\n') end
針對輸出進行修改如下:
--[out] json string function Unmarshal(lua_content) --like output lua_content --like printLuaTable --using table concat result = {} Unmarsha1Helper(lua_content,result) return table.concat(result) end --[in] lua_content:decode json to lua table --[in] result:table that convert to json string --like printLuaTable , all the element insert into result function Unmarsha1Helper(lua_content,result) if base.type(lua_content) ~= "table" then base.print [[error that lua_content is not table]] return nil,[[error in Unmarsha1Helper end]] end local isarray,arraylen = LuaArray(lua_content) if isarray and arraylen >= 1 then --array result[#result+1] = '[' for i = 1,arraylen do if base.type(lua_content[i]) == "boolean" then if lua_content[i] then result[#result+1] = [[true]] else result[#result+1] = [[false]] end elseif base.type(lua_content[i]) == "number" then result[#result+1] = '' .. lua_content[i] elseif base.type(lua_content[i]) == "string" then result[#result+1] = [["]] .. lua_content[i] .. [["]] elseif base.type(lua_content[i]) == "nil" then result[#result+1] = "null" else Unmarsha1Helper(lua_content[i],result) end result[#result+1] = ',' end if result[#result] == ',' then result[#result] = nil end result[#result+1] = ']' else --object result[#result+1] = [[{]] for k,v in base.pairs(lua_content) do result[#result+1] = '"' .. k .. '"' .. ':' if base.type(v) == "boolean" then if v then result[#result+1] = [[true]] else result[#result+1] = [[false]] end elseif base.type(v) == "number" then result[#result+1] = '' .. v elseif base.type(v) == "string" then result[#result+1] = [["]] .. v .. [["]] elseif base.type(v) == "nil" then result[#result+1] = "null" else Unmarsha1Helper(v,result) end result[#result+1] = ',' end if result[#result] == ',' then result[#result] = nil end result[#result+1] = [[}]] end end
關於lua與json的解析與反解析的基本實現就完成了,本地可以調試通過,接下來就是細致功能的完成和程序健壯性的調整了。
五.編寫程序的一些心得
程序的實現過程中也利用了SciTE進行了單步的調試,因為實現完畢之后出現了很多奇怪的問題,死循環,輸出不符合語氣。用起來感覺SciTE的調試功能還算可以,幫助完成了本地版功能的實現;
實現的過程中同樣感受到瀏覽了一遍lua程序設計之后能夠記住的東西實在太少,基本的循環結構可能都不記得,當這個程序完成之后還是需要lua的繼續學習,這樣應該才算夠學習了這門語言吧。
六.unicode碼知識
關於unicode與utf8的關系,這篇文章講的非常的詳細:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
unicode只是一個符號集合,並沒有規定具體的如何存儲,所以如何存儲還需要具體的方案,比如utf8,utf16等等。unicode與utf8的關系如下:
Unicode符號范圍 | UTF-8編碼方式
(十六進制) | (二進制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
所以這里只需要把json中的\uXXXX編碼轉換為utf8字節碼即可。