lua學習項目筆記

    這幾天草草的瀏覽了一下電子版的《lua程序設計》,沒有懂的地方就自動忽略了,挑揀了一些能夠理解的部分一直在推動。推動至後面的時候已經渾渾噩噩的了,有種想看完這本書的強迫症的感受。推動CAPI部分的時候發現難度一會兒提高了,有種難以理解的感受,並且這本書沒有相對應的練習,只是看書沒有進行相應的實踐,確實難度比較大。這裏先暫緩推動這本書的進程,決定拿一下小的項目來試試寫lua代碼的感受,寫完這個項目在回去體會lua程序設計這本書,這樣可能效果會更好一些。這裏我會列出項目描述,並且會記錄完成這個項目的過程,固然,項目是一個很是簡單,並且已經存在優秀的開源庫的東西,可是這裏先檢查一下本身是否可以完成,完成以後能夠參閱一下相關開源庫的實現,對比之中應該會有所提升。html

項目描述:python

基於lua 5.2.3 封裝實現一個可供其餘lua腳本使用的功能模塊,具體要求爲:
    一、實現一個標準的lua功能模塊
    二、封裝json格式的數據與lua value間的互相轉換功能
    三、遵循json格式定義確保相同的數據源彼此轉換後數據仍然一致
    四、只容許使用lua內建基礎庫,不容許使用任何第三方開發庫
    五、有合理的註釋和單元測試代碼
    六、獨立完成此做業,對任何代碼抄襲現象零容忍

基本要求:
提交lua代碼文件名爲json.lua,測試代碼和文檔(若是有)能夠打一個包做爲第二個附件提交
json.lua中須要實現如下接口:
	function Marshal(json_str) return lua_val end
	function Unmarshal(lua_val) return "json_str" end

對基本要求的說明:
	一、lua版本要求5.2.3	
	二、lua的空table統一轉化成json的空object,而不是空array
	三、test case中的json_str符合ECMA-404 json格式標準
	四、Unmarshal傳入的lua_val若是是table的話,不會有循環嵌套
	五、table若是是以array方式使用,轉換以下:{[2]=1,[4]=1} == {nil,1,nil,1} <-> [null,1,null,1]
	六、table中有string key時,統一處理成hash table的格式,如:{1,2;a=3} -> {"1":1,"2":2","a":3}
	七、不會出現相似 {1,2;["2"]="same key 2 in json"} 形成轉換有歧義的table
	八、Unicode轉成lua字符串時,按lua的字符串格式 \xXX\xYY...
	九、能成功轉換的話,只須要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

 

項目解決過程:正則表達式

一.模塊json

    首先這個問題是實現一個模塊,在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字節碼便可。

相關文章
相關標籤/搜索