这几天草草的浏览了一下电子版的《lua程序设计》,没有懂的地方就自动忽略了,挑拣了一些可以理解的部分一直在推进。推进至后面的时候已经浑浑噩噩的了,有种想看完这本书的强迫症的感觉。推进CAPI部分的时候发现难度一下子提升了,有种难以理解的感觉,而且这本书没有相对应的练习,只是看书没有进行相应的实践,确实难度比较大。这里先暂缓推进这本书的进程,决定拿一下小的项目来试试写lua代码的感觉,写完这个项目在回去体会lua程序设计这本书,这样可能效果会更好一些。这里我会列出项目描述,而且会记录完成这个项目的过程,当然,项目是一个非常简单,而且已经存在优秀的开源库的东西,但是这里先检查一下自己是否能够完成,完成之后可以参阅一下相关开源库的实现,对比之中应该会有所提高。

项目描述:

  1. 基于lua 5.2.3 封装实现一个可供其他lua脚本使用的功能模块,具体要求为:
  2. 1、实现一个标准的lua功能模块
  3. 2、封装json格式的数据与lua value间的互相转换功能
  4. 3、遵循json格式定义确保相同的数据源彼此转换后数据仍然一致
  5. 4、只允许使用lua内建基础库,不允许使用任何第三方开发库
  6. 5、有合理的注释和单元测试代码
  7. 6、独立完成此作业,对任何代码抄袭现象零容忍
  8.  
  9. 基本要求:
  10. 提交lua代码文件名为json.lua,测试代码和文档(如果有)可以打一个包作为第二个附件提交
  11. json.lua中需要实现以下接口:
  12. function Marshal(json_str) return lua_val end
  13. function Unmarshal(lua_val) return "json_str" end
  14.  
  15. 对基本要求的说明:
  16. 1lua版本要求5.2.3
  17. 2lua的空table统一转化成json的空object,而不是空array
  18. 3test case中的json_str符合ECMA-404 json格式标准
  19. 4Unmarshal传入的lua_val如果是table的话,不会有循环嵌套
  20. 5table如果是以array方式使用,转换如下:{[2]=1,[4]=1} == {nil,1,nil,1} <-> [null,1,null,1]
  21. 6table中有string key时,统一处理成hash table的格式,如:{1,2;a=3} -> {"1":1,"2":2","a":3}
  22. 7、不会出现类似 {1,2;["2"]="same key 2 in json"} 造成转换有歧义的table
  23. 8、Unicode转成lua字符串时,按lua的字符串格式 \xXX\xYY...
  24. 9、能成功转换的话,只需要return单个值
  25.  
  26. 进阶要求:
  27. 对test case的错误进行检查,返回相应错误
  28. function Marshal(json_str) return nil, "error_type" end
  29.  
  30. 基本测试方法:
  31. local json = require 'json'
  32.  
  33. local test_result1 = json.Marshal('{"a":1}')
  34. local test_result2 = json.Unmarshal{ b="cd" }
  35.  
  36. -- 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函数的更加详细部分以及模块编写的公共部分演化这里略去。

  1. local modname = ...
  2. local M = {}
  3. _G[modname] = M
  4. package.loaded[modname] = M
  5.  
  6. <setup for external access>
  7.  
  8. setfenv(1,M)

关于子模块和包的部分这里也利用不到,所以这部分知识也略去,关于lua程序设计一书中这部分讲述也稍有复杂,其中印刷题中关于'-'和'_'区分不好,看起来比较吃力,不过关于require和module的部分讲解的非常不错。

所以这部分的代码实现如下:

  1. module(...,package.seeall)
  2.  
  3. function Marshal(json_str)
  4. print(json_str)
  5. end
  6.  
  7. function Unmarshal(lua_content)
  8. print(lua_content)
  9. 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码的转换后面进行解释;

  1. json_to_lua = {
  2. ['\\"] = '"',
  3. ['\\/'] = '/',
  4. ['\\\\'] = '\\'
  5. ["\\t"] = "\t",
  6. ["\\f"] = "\f",
  7. ["\\r"] = "\r",
  8. ["\\n"] = "\n",
  9. ["\\b"] = "\b"
  10. }
  11. lua_json = {
  12. ['"'] = '\\"',
  13. ['\\'] = '\\\\',
  14. ['/'] = '\\/',
  15. ['\b'] = '\\b',
  16. ['\f'] = '\\f',
  17. ['\n'] = '\\n',
  18. ['\r'] = '\\r',
  19. ['\t'] = '\\t'
  20. }

数字的自动机转移图,其中数字包含正负类型,浮点数,整型,科学技术法,所以合法的数字类型的状态机比较复杂,但是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字符串存在格式错误。

  1. --two interface encode json or decode json
  2. function M.Marshal(json_str)
  3.  
  4. local nowTime = os.time()
  5.  
  6. --json must be json array or object
  7. local position = 1
  8. position = M.skipBlank(json_str,position)
  9. --null json string case
  10. local json_len = string.len(json_str)
  11. if position > json_len then
  12. return nil,[[null json string]]
  13. end
  14. --change to json object or json array
  15. --otherwise,invalid
  16. local c = string.sub(json_str,position,position)
  17. local res
  18. if c == [[{]] then
  19. res = M.decodeObject(json_str,position)
  20. elseif c == [[[]] then
  21. res = M.decodeArray(json_str,position)
  22. else
  23. res = nil,[[error that json no an object or array,invalid]]
  24. end
  25.  
  26. M.MarshalTime = M.MarshalTime + os.time() - nowTime
  27.  
  28. return res
  29. 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中的一个即可

  1. --skip the blank character
  2. --blank character include space,\n \r \t
  3. --params
  4. --[in] json_str : json string
  5. --[in] position : current position of the string
  6. --[out] the next of end position of the blank character
  7. function skipBlank(json_str,position)
  8. local blankcharacter = ' \t\r\n'
  9. local json_len = string.len(json_str)
  10. while position <= json_len do
  11. local c = string.sub(json_str,position,position)
  12. --malformed pattern (missing ']'),error
  13. if c == "[" then
  14. return position
  15. elseif string.find(blankcharacter,c) then
  16. position = position + 1
  17. else
  18. break
  19. end
  20. end
  21. return position
  22. end

解析json object

函数看似比较复杂,其实逻辑比较清晰;

json object开始于 '{',结束于 '}',由key:value对组成,由 ',' 分隔;

不断的读取key , ':' , value 然后填入相应的lua table,返回lua table即可;

其中利用计数的方法保证 ',' 的语法正确;

  1. --decode from json object
  2. --begin with '{'
  3. --params
  4. --[in] json_str : json string
  5. --[in] position : current position of the string
  6. --[out] lua table , the next of end the end position of the string
  7. function decodeObject(json_str,position)
  8. local lua_object = {}
  9. local key,subobject,subarray,str,number,othervalue
  10. local c = string.sub(json_str,position,position)
  11. --check case
  12. if c ~= [[{]] then
  13. base.print [[error that object not start with { ]]
  14. return nil,[[error in decodeObject begin]]
  15. end
  16. position = position + 1
  17. position = skipBlank(json_str,position)
  18. c = string.sub(json_str,position,position)
  19. if c == [[}]] then
  20. position = position + 1
  21. return lua_object,position
  22. end
  23. --then json array including {key:value,key:value,key:value,...}
  24. --key --> string
  25. --value including
  26. --string
  27. --number
  28. --object
  29. --array
  30. --true,false,nil
  31. ----------------------------------------------------------------
  32. local precount = -1
  33. local curcount = 0
  34. local json_len = string.len(json_str)
  35. while position <= json_len do
  36. position = skipBlank(json_str,position)
  37. c = string.sub(json_str,position,position)
  38. --key:value
  39. if c == [[}]] then
  40. --object over
  41. if precount >= curcount then
  42. --,is adjace to ]
  43. base.print "error that , is adjace to }"
  44. return nil,"error that , is adjace to }"
  45. end
  46. break
  47. elseif c == [[,]] then
  48. --next key:value or over
  49. position = position + 1
  50. precount = precount + 1
  51. if 0 == curcount then
  52. --,is the first,error
  53. base.print [[error that , in key:value is the first]]
  54. return nil,[[error that , in key:value is the first]]
  55. end
  56. if precount >= curcount then
  57. --,is more than one
  58. base.print [[error that , in key:value is more than one]]
  59. return nil,[[error that , in key:value is more than one]]
  60. end
  61. elseif c == [["]] then
  62. --begin key:value
  63. key,position = decodeString(json_str,position)
  64. --:
  65. position = skipBlank(json_str,position)
  66. c = string.sub(json_str,position,position)
  67. if c ~= [[:]] then
  68. base.print [[error,that object not key:value format]]
  69. return nil,[[error in decodeObject,format error]]
  70. else
  71. position = position + 1
  72. end
  73. --begin value
  74. position = skipBlank(json_str,position)
  75. c = string.sub(json_str,position,position)
  76. if c == '[' then
  77. subarray,position = decodeArray(json_str,position)
  78. lua_object[key] = subarray
  79. elseif c == '{' then
  80. subobject,position = decodeObject(json_str,position)
  81. lua_object[key] = subobject
  82. elseif c == [["]] then
  83. str,position = decodeString(json_str,position)
  84. lua_object[key] = str
  85. elseif string.find([[+-0123456789.e]],c) then
  86. number,position = decodeNumber(json_str,position)
  87. lua_object[key] = number
  88. else
  89. othervalue,position = decodeOther(json_str,position)
  90. if othervalue then
  91. lua_object[key] = othervalue
  92. end
  93. end
  94. if not lua_object[key] then
  95. base.print [[error in json object key:value --> value,can't get value]]
  96. return nil,[[error in decodeObject value]]
  97. else
  98. curcount = curcount + 1
  99. end
  100. --end value
  101. else
  102. base.print [[error json format]]
  103. return nil,[[error json format,in decodeObject end]]
  104. end
  105. end
  106. return lua_object,position + 1
  107. end

解析json array

json array的解析开始于 '[' 符号,结束于 ']' 符号,value值之间利用 ',' 隔开;

创建一个lua table,针对value值利用 t[#t+1] = value插入新的值,新的值根据符号调用相应的decode方法即可,

其中为了确保json语法错误被检测出来,利用计数的方法保证 ',' 语法的正确;

  1. --decode from json array
  2. --begin with '['
  3. --params
  4. --[in] json_str : json string
  5. --[in] position : current position of the string
  6. --[out] lua table , the next of end the end position of the string
  7. function decodeArray(json_str,position)
  8. local lua_array = {}
  9. local c = string.sub(json_str,position,position)
  10. --check case
  11. if c ~= [[[]] then
  12. base.print [[error that array not start with [ ]]
  13. return nil,[[error in decodeArray begin]]
  14. end
  15. position = position + 1
  16. position = skipBlank(json_str,position)
  17. c = string.sub(json_str,position,position)
  18. if c == ']' then
  19. position = position + 1
  20. return lua_array,position
  21. end
  22. --then json array including [value,value,value...]
  23. --value including
  24. --string
  25. --number
  26. --object
  27. --array
  28. --true,false,nil
  29. -------------------------------------------------------------------------
  30. --about [,] or ["hello",] or [,"hello"] or ["hello",,"world"] check error
  31. --using pre count & cur count to find this
  32. local precount = -1
  33. local curcount = 0
  34. local json_len = string.len(json_str)
  35. while position <= json_len do
  36. position = skipBlank(json_str,position)
  37. c = string.sub(json_str,position,position)
  38. if c == '[' then
  39. subarray,position = decodeArray(json_str,position)
  40. lua_array[#lua_array+1] = subarray
  41. curcount = curcount + 1
  42. elseif c == '{' then
  43. subobject,position = decodeObject(json_str,position)
  44. lua_array[#lua_array+1] = subobject
  45. curcount = curcount + 1
  46. elseif c == [["]] then
  47. str,position = decodeString(json_str,position)
  48. lua_array[#lua_array+1] = str
  49. curcount = curcount + 1
  50. elseif string.find([[+-0123456789.e]],c) then
  51. number,position = decodeNumber(json_str,position)
  52. lua_array[#lua_array+1] = number
  53. curcount = curcount + 1
  54. elseif c == ']' then
  55. --there is some bugs,which is end with ,
  56. if precount >= curcount then
  57. --,is adjace to ]
  58. base.print "error that , is adjace to ]"
  59. return nil,"error that , is adjace to ]"
  60. end
  61. break
  62. elseif c == ',' then
  63. --there is some bugs,which is begin with ,
  64. position = position + 1
  65. precount = precount + 1
  66. if 0 == curcount then
  67. --,is the first,error
  68. base.print [[error that , is the first]]
  69. return nil,[[error that , is the first]]
  70. end
  71. if precount >= curcount then
  72. --,is more than one
  73. base.print [[error that , is more than one]]
  74. return nil,[[error that , is more than one]]
  75. end
  76. else
  77. othervalue,position = decodeOther(json_str,position)
  78. lua_array[#lua_array+1] = othervalue
  79. curcount = curcount + 1
  80. end
  81. end
  82.  
  83. if position > json_len then
  84. base.print 'error that array not end with ]'
  85. return nil,[[error in decodeArray end]]
  86. end
  87. c = string.sub(json_str,position,position)
  88. if c ~= ']' then
  89. base.print 'error that array not end with ]'
  90. return nil,[[error in decodeArray end]]
  91. end
  92. position = position + 1
  93. return lua_array,position
  94. end 

解析json string

关于unicode的部分还未实现,还不是很了解这方面的知识;

关于string的解析仅仅是从第一个双引号开始,找到最后一个双引号且不是[[\"]],及转义的双引号,然后截取两个双引号之间的内容,得到字符串即可;

  1. --decode json string,include json key of key/value and the string value
  2. --begin with ' " '
  3. --params
  4. --[in] json_str : json string
  5. --[in] position : current position of the string
  6. --[out] lua string , the next of end the end position of the string
  7. function M.decodeString(json_str,position)
  8.  
  9. nowTime = os.time()
  10.  
  11. local endposition = position + 1
  12. local json_len = string.len(json_str)
  13. while endposition <= json_len and ( [["]] ~= string.sub(json_str,endposition,endposition) or [[\]] == string.sub(json_str,endposition - 1,endposition - 1) ) do
  14. endposition = endposition + 1
  15. end
  16. local str = string.sub(json_str,position + 1,endposition - 1)
  17.  
  18. --process str
  19.  
  20. str = string.gsub(str,'\\u....',function (tstr)
  21. local a = string.sub(tstr,3,6)
  22. local n = tonumber(a,16)
  23. local x
  24. if n < 0x80 then
  25. x = string.char(n % 0x80)
  26. elseif n < 0x800 then
  27. -- [110x xxxx] [10xx xxxx]
  28. x = string.char(0xC0 + (math.floor(n/64) % 0x20), 0x80 + (n % 0x40))
  29. else
  30. -- [1110 xxxx] [10xx xxxx] [10xx xxxx]
  31. x = string.char(0xE0 + (math.floor(n/4096) % 0x10), 0x80 + (math.floor(n/64) % 0x40), 0x80 + (n % 0x40))
  32. end
  33. return x
  34. end
  35. )
  36. str = string.gsub(str,'\\.',escapeSequences)
  37. return str,endposition + 1
  38. end

当然这其中有些转义字符的处理,均利用string.gsub函数,针对相应字符如果table中包含,则进行替换,相关table和函数如下。

  1. local ecapses = {
  2. ['"'] = '\\"',
  3. ['\\'] = '\\\\',
  4. ['/'] = '\\/',
  5. ['\b'] = '\\b',
  6. ['\f'] = '\\f',
  7. ['\n'] = '\\n',
  8. ['\r'] = '\\r',
  9. ['\t'] = '\\t'
  10. }
  11. function encodeString(s)
  12. return string.gsub(s,'.',function(c) return ecapses[c] end)
  13. end
  14.  
  15. local escapeSequences = {
  16. ["\\t"] = "\t",
  17. ["\\f"] = "\f",
  18. ["\\r"] = "\r",
  19. ["\\n"] = "\n",
  20. ["\\b"] = "\b"
  21. }
  22. setmetatable(escapeSequences, {__index = function(t,k)
  23. -- skip "\" aka strip escape
  24. return string.sub(k,2)
  25. end})

解析json number

这里实现number的解析也比较偷懒,获取到连续的比较像number的字符串,利用lua提供的tonumber函数转换为number,失败返回nil

  1. --decode json number
  2. --the valid number of json,include float,int and so on
  3. --[in] json_str : json string
  4. --[in] position : current position of the string
  5. --[out] lua number , the next of end the end position of the string
  6. function decodeNumber(json_str,position)
  7. --string to number,lua have this function - tonumber
  8. local acceptCharacter = [[+-0123456789.e]]
  9. if not string.find(acceptCharacter,string.sub(json_str,position,position)) then
  10. base.print [[error that string not start with " ]]
  11. return nil,[[error in decodeNumber begin]]
  12. end
  13. --find the endposition
  14. local endposition = position
  15. local json_len = string.len(json_str)
  16. while endposition <= json_len and string.find(acceptCharacter,string.sub(json_str,endposition,endposition)) do
  17. endposition = endposition + 1
  18. end
  19. local number = base.tonumber(string.sub(json_str,position,endposition - 1))
  20. if not number then
  21. base.print [[error in number format]]
  22. return nil,[[error in decodeNumber end]]
  23. end
  24. return number,endposition
  25. end 

解析json的一些常量

关于json中的常量包含true,false和null,解析得到相应的值即可;

  1. --decode other json value
  2. --include boolean value(true,false) or null
  3. --[in] json_str : json string
  4. --[in] position : current position of the string
  5. --[out] lua boolean or nil , the next of end the end position of the string
  6. function decodeOther(json_str,position)
  7. --true,false,null,
  8. --three value
  9. -- "true" --> true
  10. -- "false"--> false
  11. -- "null" --> nil
  12. OtherString = {"true","false","null"}
  13. JsonLua = { ["true"] = true,["false"] = false,["null"] = nil }
  14. for i = 1,#OtherString do
  15. local str = OtherString[i]
  16. if string.sub(json_str,position,position + string.len(str) - 1) == str then
  17. return JsonLua[str],position + string.len(str)
  18. end
  19. end
  20. base.print [[error,invalid json other,not true,false,null]]
  21. return nil,[[error in decodeOther end]]
  22. end

(2)lua内部对象转换json

这部分比较简单,也存在一种可能是我考虑的比较简单,目前感觉实现还是正确的,因为我在debug上面的时候实现了一个printLua函数,打印json转换为lua table的内部结构;

打印出的结构刚好比较类似json的结构,所以后面只需要针对这个函数进行修改,输出部分改为输出至string即可

关于printLua函数:

这个函数的一个辅助函数是判断lua中的table是否为数组形式,或者是键值对的形式;

  1. --this function check lua_table is array or is an object
  2. --compare to json
  3. --if there exists one key/value in the lua_table,it's an object,otherwise,it's an array
  4. --[in] lua_table : table type in lua
  5. --[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
  6. function LuaArray(lua_table)
  7. --if lua_table is an array,it imply that all its key's type is number
  8. --if lua_table is an key/value table,imply that there exists string type in its keys
  9. --so just check all its key type
  10. local isarray = true
  11. local maxindex = 0
  12. for k,_ in base.pairs(lua_table) do
  13. if base.type(k) ~= [[number]] then
  14. isarray = false
  15. break
  16. elseif base.type(k) == [[number]] and (math.floor(k) ~= k or k < 1) then
  17. isarray = false
  18. break
  19. else
  20. maxindex = math.max(maxindex,k)
  21. end
  22. end
  23. return isarray,maxindex
  24. end
  25. --for test lua Table
  26. --output lua table
  27. --format output table
  28. function printLuaTable(luaT,space)
  29. local ss = string.rep([[ ]],space)
  30. local isarray,alen = LuaArray(luaT)
  31. if isarray then
  32. io.write(ss .. '[\n')
  33. for i = 1,alen do
  34. io.write(ss .. [[ ]])
  35. if base.type(luaT[i]) == "boolean" then
  36. if luaT[i] then
  37. io.write('true\n')
  38. else
  39. io.write('false\n')
  40. end
  41. elseif base.type(luaT[i]) == "number" then
  42. io.write(luaT[i] .. '\n')
  43. elseif base.type(luaT[i]) == "string" then
  44. io.write(luaT[i] .. '\n')
  45. elseif base.type(luaT[i]) == "nil" then
  46. io.write('nil\n')
  47. else
  48. printLuaTable(luaT[i],space + 4)
  49. end
  50. end
  51. io.write(ss .. ']\n')
  52. else
  53. io.write(ss .. '{\n')
  54. for k,v in base.pairs(luaT) do
  55. local str = [[ ]] .. k .. ':'
  56. io.write(ss .. str)
  57. if base.type(v) == "boolean" then
  58. if v then
  59. io.write('true\n')
  60. else
  61. io.write('false\n')
  62. end
  63. elseif base.type(v) == "number" then
  64. io.write(v .. '\n')
  65. elseif base.type(v) == "string" then
  66. io.write(v .. '\n')
  67. else
  68. printLuaTable(v,space + 4)
  69. end
  70. end
  71. end
  72. io.write(ss .. '}\n')
  73. end

针对输出进行修改如下:

  1. --[out] json string
  2. function Unmarshal(lua_content)
  3. --like output lua_content
  4. --like printLuaTable
  5. --using table concat
  6. result = {}
  7. Unmarsha1Helper(lua_content,result)
  8. return table.concat(result)
  9. end
  10. --[in] lua_content:decode json to lua table
  11. --[in] result:table that convert to json string
  12. --like printLuaTable , all the element insert into result
  13. function Unmarsha1Helper(lua_content,result)
  14. if base.type(lua_content) ~= "table" then
  15. base.print [[error that lua_content is not table]]
  16. return nil,[[error in Unmarsha1Helper end]]
  17. end
  18. local isarray,arraylen = LuaArray(lua_content)
  19. if isarray and arraylen >= 1 then
  20. --array
  21. result[#result+1] = '['
  22. for i = 1,arraylen do
  23. if base.type(lua_content[i]) == "boolean" then
  24. if lua_content[i] then
  25. result[#result+1] = [[true]]
  26. else
  27. result[#result+1] = [[false]]
  28. end
  29. elseif base.type(lua_content[i]) == "number" then
  30. result[#result+1] = '' .. lua_content[i]
  31. elseif base.type(lua_content[i]) == "string" then
  32. result[#result+1] = [["]] .. lua_content[i] .. [["]]
  33. elseif base.type(lua_content[i]) == "nil" then
  34. result[#result+1] = "null"
  35. else
  36. Unmarsha1Helper(lua_content[i],result)
  37. end
  38. result[#result+1] = ','
  39. end
  40. if result[#result] == ',' then
  41. result[#result] = nil
  42. end
  43. result[#result+1] = ']'
  44. else
  45. --object
  46. result[#result+1] = [[{]]
  47. for k,v in base.pairs(lua_content) do
  48. result[#result+1] = '"' .. k .. '"' .. ':'
  49. if base.type(v) == "boolean" then
  50. if v then
  51. result[#result+1] = [[true]]
  52. else
  53. result[#result+1] = [[false]]
  54. end
  55. elseif base.type(v) == "number" then
  56. result[#result+1] = '' .. v
  57. elseif base.type(v) == "string" then
  58. result[#result+1] = [["]] .. v .. [["]]
  59. elseif base.type(v) == "nil" then
  60. result[#result+1] = "null"
  61. else
  62. Unmarsha1Helper(v,result)
  63. end
  64. result[#result+1] = ','
  65. end
  66. if result[#result] == ',' then
  67. result[#result] = nil
  68. end
  69. result[#result+1] = [[}]]
  70. end
  71. 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字节码即可。

lua学习项目笔记的更多相关文章

  1. Lua学习笔记6:C++和Lua的相互调用

        曾经一直用C++写代码.话说近期刚换工作.项目组中的是cocos2dx-lua,各种被虐的非常慘啊有木有.     新建cocos2dx-lua项目.打开class能够发现,事实上就是C++项 ...

  2. [转]LUA 学习笔记

    Lua 学习笔记 入门级 一.环境配置 方式一: 1.资源下载http://www.lua.org/download.html 2.用src中的源码创建了一个工程,注释调luac.c中main函数,生 ...

  3. Lua学习笔记(二):基本语法

    Lua学习指南:http://www.lua.org/manual/ 首先我们要明确的一点是:在Lua中,除了关键字外一切都是变量. Lua关键字 可以查看这个地址:http://www.lua.or ...

  4. Lua 学习笔记(一)

    Lua学习笔记 1.lua的优势 a.可扩张性     b.简单     c.高效率     d.和平台无关 2.注释 a.单行注释 --        b.多行注释 --[[  --]] 3.类型和 ...

  5. Lua学习笔记4. coroutine协同程序和文件I/O、错误处理

    Lua学习笔记4. coroutine协同程序和文件I/O.错误处理 coroutine Lua 的协同程序coroutine和线程比较类似,有独立的堆栈.局部变量.独立的指针指令,同时又能共享全局变 ...

  6. (转)Lua学习笔记1:Windows7下使用VS2015搭建Lua开发环境

    Lua学习笔记1:Windows7下使用VS2015搭建Lua开发环境(一)注意:工程必须添加两个宏:“配置属性”/“C或C++”/“预处理器”/“预处理器定义”,添加两个宏:_CRT_SECURE_ ...

  7. Lua学习笔记:面向对象

    Lua学习笔记:面向对象 https://blog.csdn.net/liutianshx2012/article/details/41921077 Lua 中只存在表(Table)这么唯一一种数据结 ...

  8. 李宏毅强化学习完整笔记!开源项目《LeeDeepRL-Notes》发布

    Datawhale开源 核心贡献者:王琦.杨逸远.江季 提起李宏毅老师,熟悉强化学习的读者朋友一定不会陌生.很多人选择的强化学习入门学习材料都是李宏毅老师的台大公开课视频. 现在,强化学习爱好者有更完 ...

  9. Lua学习高级篇

    Lua学习高级篇 之前已经说了很多,我目前的观点还是那样,在嵌入式脚本中,Lua是最优秀.最高效的,如果您有不同的观点,欢迎指正并讨论,切勿吐槽.这个系列完全来自于<Programming in ...

随机推荐

  1. C#执行OracleHelper

    /// <summary> /// 执行存储过程获取带有Out的参数 /// </summary> /// <param name="cmdText" ...

  2. CoreCLR中超过3万行代码的gc.cpp文件的来源

    在CoreCLR的开源代码中,GC的主要实现代码gc.cpp文件大小竟然有1.17MB,打开文件一看,竟然有35490行!第一次见到如此多行的单个代码文件. github都不让直接查看:https:/ ...

  3. 集群NAS技术架构

    http://blog.csdn.net/liuaigui/article/details/6422700

  4. c++如何遍历删除map/vector里面的元素

    新技能Get! 问题 对于c++里面的容器, 我们可以使用iterator进行方便的遍历. 但是当我们通过iterator对vector/map等进行修改时, 我们就要小心了, 因为操作往往会导致it ...

  5. C#课外实践——校园二手平台(技术篇3)

    说明:生活中,又有谁,能真正摆脱周围环境的束缚,而追随自己的内心呢? ListView的简单用法. 最后展示几张效果图吧 主窗体 登录窗体,虽然没有角色 选择,但已经隐藏在代码里了. 选择购买窗体,这 ...

  6. 由于外键的存在引发的一个mysql问题 Cannot change column 'id': used in a foreign key constraint

    Duplicate entry ' for key 'PRIMARY' 一查,发现表没有设置自增长. 尝试增加修改表,添加自增长. ALTER TABLE sh_incentive_item MODI ...

  7. iis6.0报以下的错。。

    Could not load file or assembly 'System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec8 ...

  8. java 解析xml

    http://developer.51cto.com/art/200903/117512.htm

  9. javascript 函数详解2 -- arguments

    今天我们接着上篇文章来继续javascript函数这个主题.今天要讲的是函数对像中一个很重要的属性--arguments. 相关阅读: javascript 函数详解1 -- 概述 javascrip ...

  10. atitit.提升2--3倍开发效率--cbb体系的建设..

    atitit.提升开发效率--cbb体系的建设.. #--提升倍数,大概2--3倍.. #---cbb的内容 知识的,expt的,经验的技术的部件的问题库的角度.. #---cbb的层次,tech l ...