lua 小技巧

  1. 把常用的工具函数添加到 _G 里面,所有的文件都可以直接调用:

    -- 在 a 文件中将工具函数添加到 _G:
    _G.IsEmptyStr = function(str)
    return str==nil or type(str) ~= "string" or str == ""
    end
    _G.PrintObjPos = function(prefix, obj)
    prefix = prefix or ""
    local l,t,r,b = obj:GetObjPos()
    XLPrint(prefix .. " l=" .. l .. ", t=" .. t .. ", r=" .. r .. ", b=" .. b)
    end -- 在其它文件中直接使用工具函数:
    if not IsEmptyStr(obj:GetText()) then
    PrintObjPos("[Dongyu]", obj)
    end
  2. 使用 or 操作符赋默认值:

    num = num or 0
  3. 使用 (a and b) or c 操作符实现 C 语言中 a ? b : c 的功能 :

    num = (num < 0 and 0) or num
    
    这样做的原理是:
    a and b -- 如果 a 为 false, 则返回 a, 否则返回 b
    a or b -- 如果 a 为 true, 则返回 a, 否则返回 b
  4. 获取 UTF-8 字符串中的字符数(中英文混合) :

    local function strlength(str)
    -- 计算字符串长度,中英文混合
    str = string.gsub(str, "%%", " ") -- 将%替换成" "
    local str = string.gsub(str, "[\128-\191]","")
    local _,ChCount = string.gsub(str, "[\192-\255]","")
    local _,EnCount = string.gsub(str, "[^\128-\255]","")
    return ChCount + EnCount
    end

    这种做法跟 UTF-8 格式有关,标准 ASC|| 码(英文)是 0-127 ;中文占 3 个字符(192-255)(128-191)(128-191);

    详情可参考这篇文章

  5. 去除字符串首尾空格:

    function trim (s)
    return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
    end
  6. 关闭 string.find(s, pattern, start, plain) 的模式匹配:

    -- 将 find 的第四个参数设定为 true, 则 pattern 将被视为普通字符串,不会处理特殊字符
    pos = string.find(str, "%s", 1, true)
  7. 分割字符串:

    function split(s, delim)
    if type(delim) ~= "string" or string.len(delim) <= 0 then
    return
    end local start = 1
    local t = {}
    while true do
    local pos = string.find (s, delim, start, true) -- plain find
    if not pos then
    break
    end table.insert (t, string.sub (s, start, pos - 1))
    start = pos + string.len (delim)
    end
    table.insert (t, string.sub (s, start)) return t
    end
  8. table.concat 打印数组:

    local t = {"2016", "3", "6"}
    print(table.concat(t, "-")) -- 2016-3-6
  9. 打印 table:

    function print_lua_table (lua_table, indent)
    local function print_func(str)
    XLPrint("[Dongyu] " .. tostring(str))
    end if lua_table == nil or type(lua_table) ~= "table" then
    print_func(tostring(lua_table))
    return
    end indent = indent or 0
    for k, v in pairs(lua_table) do
    if type(k) == "string" then
    k = string.format("%q", k)
    end
    local szSuffix = ""
    if type(v) == "table" then
    szSuffix = "{"
    end
    local szPrefix = string.rep(" ", indent)
    formatting = szPrefix.."["..k.."]".." = "..szSuffix
    if type(v) == "table" then
    print_func(formatting)
    print_lua_table(v, indent + 1)
    print_func(szPrefix.."},")
    else
    local szValue = ""
    if type(v) == "string" then
    szValue = string.format("%q", v)
    else
    szValue = tostring(v)
    end
    print_func(formatting..szValue..",")
    end
    end
    end
  10. 拷贝 table:

    function copy_table(ori_tab)
    if type(ori_tab) ~= "table" then
    return
    end
    local new_tab = {}
    for k,v in pairs(ori_tab) do
    local vtype = type(v)
    if vtype == "table" then
    new_tab[k] = copy_table(v)
    else
    new_tab[k] = v
    end
    end
    return new_tab
    end

    function deepcopy(object)
    local lookup_table = {}
    local function _copy(object)
    if type(object) ~= "table" then
    return object
    elseif lookup_table[object] then
    return lookup_table[object]
    end local new_table = {}
    lookup_table[object] = new_table
    for index, value in pairs(object) do
    new_table[_copy(index)] = _copy(value)
    end
    return setmetatable(new_table, getmetatable(object))
    end
    return _copy(object)
    end
  11. for 循环中 remove 数组元素:

    local t = {1,2,3,3,5,3,6}
    for i,v in ipairs(t) do
    if v == 3 then
    table.remove(t,i)
    end
    end
    -- 错误,第四个 3 没有被移除,ipairs 内部会维护一个变量记录遍历的位置,
    -- remove 掉第三个数字 3 之后,ipairs 下一个返回的值是 5 而不是 3 local t = {1,2,3,3,5,3,6}
    for i=1, #t do
    if t[i] == 3 then
    table.remove(t,i)
    i = i-1
    end
    end
    -- 错误,i=i-1 这段代码没有用,i 的值始终是从 1 到 #t,for 循环里修改 i 的值不起作用 local t = {1,2,3,3,5,3,6}
    for i=#t, 1, -1 do
    if t[i] == 3 then
    table.remove(t,i)
    end
    end
    -- 正确,从后往前遍历 local t = {1,2,3,3,5,3,6}
    local i = 1
    while t[i] do
    if t[i] == 3 then
    table.remove(t,i)
    else
    i = i+1
    end
    end
    -- 正确,自己控制 i 的值是否增加
  12. table.sort(t, comp) 排序数组 :

    sort 可以将 table 数组部分的元素进行排序,需要提供 comp(a,b) 函数,如果 a 应该排到 b 前面,则 comp 要返回 true 。

    注意: 对于 a==b 的情况,一定要返回 false:

    local function comp(a,b)
    return a <= b
    end
    table.sort(t,comp)
    -- 错误,可能出现异常:attempt to compare number with nil local function comp(a,b)
    if a == nil or b == nil then
    return false
    end
    return a <= b
    end
    table.sort(t,comp)
    -- 错误,可能出现异常:invalid order function for sorting
    -- 也可能不报这个异常,但结果是错误的;

    之所以 a==b 返回true 会引发这些问题,是因为 table.sort 在实现快速排序时没有做边界检测:

    for (;;) {
    while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) // 未检测边界, i 会一直增加
    {
    if (i>=u) luaL_error(L, "invalid order function for sorting");
    lua_pop(L, 1);
    }
    while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) // 未检测边界, j 会一直减少
    {
    if (j<=l) luaL_error(L, "invalid order function for sorting");
    lua_pop(L, 1);
    }
    if (j<i) {
    lua_pop(L, 3);
    break;
    }
    set2(L, i, j);
    }

    看以上代码,如果 a==b 时返回 true 且边界上的几个值是相等的话, sort_comp 就无法阻止 i 继续增长,直到超出边界引发异常 attempt to compare number with nil;

    即使对 a 和 b 进行了非空判断,也会因为 i 超过边界而引发异常 invalid order function for sorting.

最新文章

  1. BZOJ 1051 &amp; 强联通分量
  2. JavaScript基础14——js的Math对象
  3. Oracle DB 执行用户管理的备份和恢复
  4. Python os模块--路径、文件、系统命令等操作
  5. beautifulSoup模块
  6. IO代码记忆
  7. MySQL基本应用
  8. Linux OpenGL 实践篇-3 绘制三角形
  9. HTL里面使用sling model的时候传参问题
  10. 【linux】State : Uninterruptible, pid: 3936
  11. js判断是否安装某个android app,没有安装下载该应用(websocket通信,监听窗口失去焦点事件)
  12. emmc基础技术8:操作模式4-data transfer mode
  13. 运维中的日志切割操作梳理(Logrotate/python/shell脚本实现)(转)
  14. JavaScript里的Date 对象属性及对象方法--实现简单的日历
  15. 网络编程_Python-网络模型.
  16. java创建二叉树并实现非递归中序遍历二叉树
  17. VS中添加lib与dll
  18. 主元素 II
  19. 关于MBR、GPT以及BIOS引导模式区分
  20. 类型:Ajax;问题:ajax调用ashx参数获取不到;结果:ashx文件获取$.ajax()方法发送的数据

热门文章

  1. 事务内执行sql修复的简易模板
  2. iOS:iOS开发系列–打造自己的“美图秀秀”(上)
  3. px、em、rem的区别
  4. Spring框架学习(4)spring整合hibernate
  5. minic 动作句型处理
  6. 快速把web项目部署到weblogic上
  7. ionic中ionicView的生命周期
  8. dmesg 时间转换脚本
  9. IBATIS + ORACLE(二)
  10. OJ刷题---简单password破解