lua 小技巧

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.

posted on 2015-11-27 18:11  zuibunan  阅读(4231)  评论(0编辑  收藏  举报

导航