快捷搜索:  汽车  科技

lua编程基础入门教程(学习Lua碰到的问题)

lua编程基础入门教程(学习Lua碰到的问题)如下↓:ultraman = { attr = { name = '奥特曼'}} attr = ultraman.attr attr.name = '咸蛋超人' print(ultraman.attr.name) attr.name = nil print(ultraman.attr.name) 输出: 咸蛋超人 nil改变attr 不会同时改变ultraman.attr。function ReName(arg) arg.name = '咸蛋超人' end tab = { name = '奥特曼'} ReName(tab) print(tab.name) 输出: 咸蛋超人但是 改变arg表自身 tab却不会变。function ReName(arg) arg = { name = '

文章目录
  • 三、同名传参和同名字段
  • 五、rawget()和rawset()
  • 六、在Windows上安装lua
  • 3.解压文件,(存放文件地址文件夹名全部不要出现中文最佳)5.win R cmd 输入lua或者lua53后如下即安装完成6.最后intellij idea 中推荐一个EmmyLua 使用安装比较简单,在设置setting里面选择Plugins,查找EmmyLua安装即可
  • 七、把数值转成16进制的格式
  • 八、把16进制色号转成三元数Color
  • 十、string.format() 保留3位小数
  • 十一、向上/下取整 四舍五入
  • 十二、string拆成表 (不支持中文)
  • 十三、敏感词过滤 替换成*
  • 十四、通配符 正则表达式
  • 十五、用正则实现trim()
  • 十六、字符串截取string.sub()
  • 十八、if后面跟一个方法 这个方法会运行
  • 二十一、右移: “>>” 按位与: “&”
  • 二十五、字典用table.sort()排序
  • 二十七、Lua里没有string.split()
  • 三十二、裆下日期转成表 再把表转成秒
  • 三十三、看身份证满18没有
  • 三十四、Lua没有"继承"的弊端
  • 三十五、取字符串的长度
  • 三十八、逻辑运算符的优先级
  • 四十二、墙裂推荐一个VS Code的插件: Rainbow Fart
  • 四十四、JavaBean的要求规范
  • 四十九、"逻辑与"的截断机制
  • 五十、问题:Lua的输出乱码
  • 五十一、问题:Lua不是内部或外部命令,也不是可运行的程序或批处理文件
  • 五十二、判断table里有没有某元素
  • 五十三、(不)连续表的遍历
  • 六十、方法后面不加小括号
一、遍历字典是无序的

t = { } t.a = '1' t.b = '2' t.c = '3' t.d = '4' for i v in pairs(t) do print(v) end -- 每次输出都是乱序的!!!二、Lua的遍历和C#不同

function Cnt() print('执行Cnt方法') return 3 end for i = 1 Cnt() do print(i) end 输出: 执行Cnt方法 1 2 3三、同名传参和同名字段

同名传参 第1个传参无效。

function Do(arg arg) print(arg) end Do(1 2) 输出: 2

同名字段 第2个字段无效。

a a = 1 2 print(a) 输出: 1四、传参是引用传递

表作为参数传递时 是引用传递 传的是地址。

在C#里也是这样的:
如下↓ 改变"参数表"(arg)的内容 “原来的表”(tab)也会改变。

function ReName(arg) arg.name = '咸蛋超人' end tab = { name = '奥特曼'} ReName(tab) print(tab.name) 输出: 咸蛋超人

但是 改变arg表自身 tab却不会变。

function ReName(arg) arg = { name = '咸蛋超人'} end tab = { name = '奥特曼'} ReName(tab) print(tab.name) 输出: 奥特曼

改变attr.name 会同时改变ultraman.attr.name。

如下↓:

ultraman = { attr = { name = '奥特曼'}} attr = ultraman.attr attr.name = '咸蛋超人' print(ultraman.attr.name) attr.name = nil print(ultraman.attr.name) 输出: 咸蛋超人 nil

改变attr 不会同时改变ultraman.attr。

如下↓:

ultraman = { attr = { name = '奥特曼'}} attr = ultraman.attr attr = { name = '咸蛋超人'} print(ultraman.attr.name) attr = nil print(ultraman.attr.name) 输出: 奥特曼 奥特曼

结论:

改变attr内部字段 ultraman.attr会同时改变。

但是改变attr自身 ultraman.attr不变。

在lua中 如果我想置空attr怎么办呢? 只能在方法外把它置空。
在C#中 可以给传参添加ref关键字 这样一来 置空attr 原本的attr也会被置空。

五、rawget()和rawset()

只对自身get和set 而不访问元表。

otab = { a = '我是元表a'} tab = { a = '我是a'} setmetatable(tab { __index = otab __newindex = otab}) -- 获取tab的a 与元表无瓜 print(rawget(tab 'a')) print(tab.a) print(otab.a) -- 给tab的b赋值 与元表无瓜 rawset(tab 'b' '我是b') print(tab.b) print(otab.b) 输出: 我是a 我是a 我是元表a 我是b nil六、在Windows上安装Lua

Lua下载地址: Lua:download

1.get a binary

lua编程基础入门教程(学习Lua碰到的问题)(1)

2.选择自己电脑的版本

lua编程基础入门教程(学习Lua碰到的问题)(2)

3.解压文件,(存放文件地址文件夹名全部不要出现中文最佳)

lua编程基础入门教程(学习Lua碰到的问题)(3)

4.修改环境变量

lua编程基础入门教程(学习Lua碰到的问题)(4)

5.win R cmd 输入lua或者lua53后如下即安装完成

lua编程基础入门教程(学习Lua碰到的问题)(5)

6.最后intellij idea 中推荐一个EmmyLua 使用安装比较简单,在设置setting里面选择Plugins,查找EmmyLua安装即可

lua编程基础入门教程(学习Lua碰到的问题)(6)

七、把数值转成16进制的格式

print(string.format('%x' 1221197823)) 输出: 48c9ffff八、把16进制色号转成三元数Color

比如色号是: FFA2FC 先用string.sub()把她肢解为: 红FF 绿A2 蓝FC。
再用tonumber(str 16)把16进制转为10进制 (例如: FF转为255)。
再用rgb分别除以255。
最后new一个三元数Color。

local colorString = 'FFA2FC' local r = tonumber(string.sub(colorString 1 2) 16) / 255 local g = tonumber(string.sub(colorString 3 4) 16) / 255 local b = tonumber(string.sub(colorString 5 6) 16) / 255 return UnityEngine.Color(r g b)九、去掉商里的小数

用"/"来做除法 得到的结果中总会带有小数 像这样:

print(700 / 100) print(701 / 100) 输出: 7.0 7.01

需要实现:
当结果是7.0时 去掉小数部分 结果为7。
当结果是7.01时 保留小数部分 结果为7.01。

思路: 用math.modf() 把整数部分与小数部分拆开:

local t1 t2 = math.modf(700 / 100) print(t1) print(t2) 输出: 7 0.0

再加个判断"小数部分是否为0"就好了:

function GetFixedQuotient(num1 num2) quotient = num1 / num2 local t1 t2 = math.modf(quotient) -- 去掉数字后面的.0 if t2 == 0 then return t1 else return quotient end end print(GetFixedQuotient(700 100)) print(GetFixedQuotient(701 100)) 输出: 7 7.01十、string.format() 保留3位小数

print(string.format('%.3f' 0.5)) print(string.format('%.3f' 0.0005)) print(string.format('%.3f' 0.0004)) print(string.format('%.3f' 500)) 输出: 0.500 0.001(这里四舍五入了) 0.000(这里四舍五入了) 500.000十一、向上/下取整 四舍五入

-- 取整 print('向上取整: 1 / 3 = ' .. math.ceil(1 / 3)) print('向下取整: 1 / 3 = ' .. math.floor(1 / 3)) -- 想实现四舍五入 就 0.5 print('四舍五入: 1 / 3 = ' .. math.floor(1 / 3 0.5)) print('四舍五入: 2 / 3 = ' .. math.floor(2 / 3 0.5)) -- 保留3位小数的四舍五入 就先*1000再 0.5再/1000 print('四舍五入: 1 / 3 = ' .. math.floor(1 / 3 * 1000 0.5) / 1000) print('四舍五入: 2 / 3 = ' .. math.floor(2 / 3 * 1000 0.5) / 1000) 输出: 向上取整: 1 / 3 = 1 向下取整: 1 / 3 = 0 四舍五入: 1 / 3 = 0 四舍五入: 2 / 3 = 1 四舍五入: 1 / 3 = 0.333 四舍五入: 2 / 3 = 0.667十二、string拆成表 (不支持中文)

input = "2b*)我" tabA = { } for i = 1 #input do let = string.sub(input i i) table.insert(tabA i let) print(i let) end 输出: 1 2 2 b 3 * 4 ) 5 � 6 � 7 �十三、敏感词过滤 替换成*

input = 'ABc大大大' word = 'bc大' lower = string.lower(input) result = lower if string.find(lower tostring(word)) ~= nil then -- 汉字占3个字符 所以不能直接用string.len() local _ count = string.gsub(word '[^\128-\193]' '') local stars = string.rep('*' count) result = string.gsub(lower tostring(word) stars) end print(result) 输出: A***大大十四、通配符 正则表达式

s = "abc \"it's a cat\"" _ _ _ d = string.find(s "([\"'])(.-)%1") print(d) -----输出: it's a cat十五、用正则实现trim()

name = ' 蒂纳 奥特曼 ' local _name = string.gsub(name '^%s*(.-)%s*$' '%1') print(_name) 输出:蒂纳 奥特曼十六、字符串截取string.sub()

s = 'abcde' print(string.sub(s 1 3)) -- 从1数到3 print(string.sub(s 3 3)) -- 从3数到3 print(string.sub(s 3)) -- 从3数到末尾 print(string.sub(s 8)) -- 没有8 直接空了 print(string.sub(s 3 -1)) -- 从3数到5(末尾) print(string.sub(s 3 -2)) -- 从3数到4(末尾-1) print(string.sub(s -4 -2)) --从2(末尾-3)数到4(末尾-1) print(string.sub(s -9))-- 从头数到尾 -- 输出: abc c cde cde cd bcd abcde十七、数组增删

数组能用 字典不行。

table.insert(list [pos ]value) -- 不给pos就是#list 1 table.remove(list[ pos]) -- 不给pos就是#list

注意: 在for的时候 要从后往前删。

十八、if后面跟一个方法 这个方法会运行

function fun() print(2) end if fun() then end 输出: 2

↓写成这样则不执行。

if fun then end十九、匿名函数

注意: 直接 a = fun() fun会立即执行 不想立即执行的话 就用个匿名方法把它包起来 或者像delegate的 =一样 方法后面别带括号。

function foo(arg) print(arg) end ---------1---------- arg1 = 1 -- 直接执行 输出1 fun = foo(arg1) ---------2---------- arg2 = 2 -- 不执行 fun = function() foo(arg2) end -- 执行 输出2 fun() ---------3---------- arg3 = 3 -- 不执行 fun = foo -- 执行 输出3 fun(arg3)

进阶: 2个不同来源的传参:

function fooo(arg1 arg2) print(arg1 arg2) end a = 2 -- 不执行 fun = function(b) fooo(a b) end -- 执行 输出2 3 fun(3)二十、死循环

这样写就是死循环↓:

for i = 1 i 10 do print(i) end

正确写法↓:

local endNum = i 10 for i = 1 endNum do print(i) end二十一、右移: “>>” 按位与: “&”

print(0x0000ffff) print(32794992 >> 16) print(500 & 65535) print(500 & 63) 输出: 65535 500 500 52 --------------------------------------------------------------- 先看: 0x0000ffff (得: 65535) 16进制的: 0x0000ffff 就是10进制的: 65535 就是2进制的: 11111111111111111111(16个1) (10进制的: 65536 就是2进制的: 1000000000000000000(16个0) 就是 1>>16) 再看: 32794992 >> 16 (得: 500) 10进制的: 32794992 就是2进制的: ‭1111101000110100101110000‬ 左移16位 后面16位就被丢掉了 只剩下111110100 就是10进制的: 500 (计算器算 32794992 ÷ 65536 = 500.41186523438) 再看 500 & 65535 (得: 500) 一个2进制数 只要小于16个1 它和 11111111111111(16个1) 做按位与 还是它自己 所以 500(111110100) 和 11111111111111(16个1) 做按位与 还是它自己 再看 500 & 63 10进制的: 63 就是2进制的: 111111 500(111110100) 和 111111 做按位与 就相当于高于6位的都丢掉了 结果是 110100 也就是10进制的 52

实例: id是64位 其组成为:14位没用 - 8位大区id - 10位服务器id - 32位玩家id。
需求: 取服务器id。
分析: 先右移32位 去除玩家id 再和1111111111(10个1)做按位与 就能得到10位的服务器id。

local id = 3063948711696181930 zoneID = (id >> 32) & 1023 print(zoneID)二十二、左移数值越界

local id = 3063948711696181930 -- 即‭为2进制的: 10 1010 1000 0101 0101 0101 0001 1110 1010 1010 1010 1010 1010 1010 1010 1010 zoneID = (id << 2) -- 左移2位 即后面填2个0 即为2进制的: ‭10 1010 1000 0101 0101 0101 0001 1110 1010 1010 1010 1010 1010 1010 1010 1010 00 -- 共64位 其首位是1 代表负号 print(zoneID) -- 所以打印出负数: -6190949226924823896二十三、可变参数: ‘…’

如果直接用表{…}来接收 将会丢失传参中的ni。
解决: 用table.pack(…)来接收 会给一个’n’作为index。

function Foo1(...) -- 用表{ ...}来接收 将会丢失传参中的nil local arg = { ...} for k v in pairs(arg) do print(v) end end Foo1('奥特曼' nil) 输出: 奥特曼 ---------------------------------- function Foo2(...) -- 用table.pack(...)来接收 会给一个'n'作为index local arg = table.pack(...) for i = 1 arg.n do print(arg[i]) end end Foo2('奥特曼' nil) 输出: 奥特曼 nil二十四、浅拷贝表

我预言: 这玩意早晚有一天会坑到我。

list = { name = 1} temp = list -- 浅拷贝 temp.name = 2 -- temp改变 list也会变 print(list.name) -- 输出2二十五、字典用table.sort()排序

table.sort()只能排数组 不能排字典。
解决方法: 把字典放进数组里。

dic = { a = { ['id'] = 12 ['order'] = 20001} b = { ['id'] = 435 ['order'] = 545} c = { ['id'] = 6 ['order'] = 2004501} d = { ['id'] = 768 ['order'] = 2} e = { ['id'] = 87 ['order'] = 22222} } array = { } index = 0 for k v in pairs(dic) do index = index 1 v.name = k array[index] = v end table.sort( array function(a b) return a.order < b.order end ) for i = 1 #array do local fmt = '%s: name:%s id:%s order:%s' print(string.format(fmt i array[i].name array[i].id array[i].order)) end 输出: 1: name:d id:768 order:2 2: name:b id:435 order:545 3: name:a id:12 order:20001 4: name:e id:87 order:22222 5: name:c id:6 order:2004501

就排好啦,注意: table.sort()里面只能写小于和大于: < > 不能带等号: <= =>。

二十六、多条件排序

local tab = { { arg1 = 5 arg2 = 2} { arg1 = 0 arg2 = 5} { arg1 = 2 arg2 = 1} { arg1 = 1 arg2 = 3} { arg1 = 1 arg2 = 4} } table.sort( tab function(a b) if a.arg1 == b.arg1 then -- 如果条件1相等 则判断条件2 return a.arg2 < b.arg2 end return a.arg1 < b.arg1 end ) for i = 1 #tab do print(tab[i].arg1 tab[i].arg2) end 输出: 0 5 1 3 1 4 2 1 5 2二十七、Lua里没有string.split()

方法1 会保留nil。

function string.split(str delimiter) if str == nil or str == '' or delimiter == nil then return nil end local result = { } for match in (str .. delimiter):gmatch('(.-)' .. delimiter) do table.insert(result match) end return result end -- 测试 local str = "1::3"; local list = string.split(str ":"); for key value in pairs(list) do print(key value) end 输出: 1 1 2 3 3

方法1 不保留nil。

function string:split(sep) local sep fields = sep or "\t" { }; local pattern = string.format("([^%s] )" sep); self:gsub(pattern function(c) fields[#fields 1] = c; end) return fields; end -- 测试 local str = "1::3"; local list = string.split(str ":"); for key value in pairs(list) do print(key value) end 输出: 1 1 2 3二十八、lua特殊写法

print (“Hello World”)阔以写成:,print “Hello World”,括号可以被省略。

lua… 你可真是怎么写都行。

二十九、变量名

lua你真是太随便了! 一点都不知道检点!这样写:

table = '奥特曼'

于是table就被重新定义了,true false nil 没法重定义,type string print 都能被重新定义。

三十、今天星期几

os.date("%w") 1是星期一 0是星期天三十一、os.time(): 秒

os.time()没参数 返回从1970年1月1日到现在的秒数 1604374105 os.time({ year=2020 month=1 day=1})返回从1970年1月1日到指定时间的秒数 1577851200 os.time({ year=2008 month=1 day=1 hour=8 min=0 sec=0 isdst=false}) 1199145601 其中 时/分/秒/夏令时 都是可选参数 不填按0算 也可以写负数就是算减法三十二、裆下日期转成表 再把表转成秒

-- 把裆下日期转化为表: year = 2080 ... tab = os.date('*t') tab.hour = 5 tab.min = 20 -- 再把表转化成秒 sec = os.time(tab)三十三、看身份证满18没有

function IsAdult(idNum) local function CheckYearOld(idNum) local dt = os.date('*t' os.time()) local year = tonumber(string.sub(idNum 7 10)) local month = tonumber(string.sub(idNum 11 12)) local day = tonumber(string.sub(idNum 13 14)) if month > dt.month then return dt.year - year - 1 elseif month == dt.month and day >= dt.day then return dt.year - year - 1 else return dt.year - year end end return CheckYearOld(idNum) >= 18 end三十四、Lua没有"继承"的弊端

Lua这门语言 因为没有"继承" 所以连IDE都骗过了 IDE没法给你提示基类的方法 因为IDE不知道谁是基类 想用基类方法 你就得掀开基类的衣服 从头到脚看一遍 用过一次就好了 聪明的IDE会记住这个"你曾用过的方法" 并给你提示三十五、取字符串的长度

string.len()里面可以写数字:

string.len(123456)

#的后面只能跟字符串:

三十六、#号

#号只能取数组的长度 字典不行。

tab = { [1] = 1 [2] = 1 [3] = 1 [4] = 1 [7] = 1 } print(#tab)

**你猜多少?输出: 4。

#号的实现原理是什么?**

lua5.2中没有了getn函数。那么常用的取长度方式为# 而#的使用又有些需要注意的地方。
首先要明确的是lua中有两部分:数组部分和hash表部分。而基本上所有操作都是先数组后hash表。

local test1 = { 1 2 3 4 5 } print(#test1) 打印结果: 5 local test1 = { 1 3 5 2 4 } print(#test1) 打印结果: 5 (好吧。。。。当然跟上面一样,都是作为数组中的值。。。) local test1 = { [1] = 1 [2] = 2 [3] = 3 [4] = 4 [5] = 5} print(#test1) 打印结果: 5 (这里table中没有数组部分了,只有hash表部分) local test1 = { [1] = 1 [3] = 3 [4] = 4 [6] = 6 [2] = 2} print(#test1) 打印结果: 6 for i = 1 #test1 do print(test1[i]) end 如果全部打印出来 1 2 3 4 nil 6

明明写的table中只有5个元素,怎么会变成6那。。。。这里的原因就要看下lua源码实现。

/* ** Try to find a boundary in table `t'. A `boundary' is an integer index ** such that t[i] is non-nil and t[i 1] is nil (and 0 if t[1] is nil). */ int luaH_getn (Table *t) { unsigned int j = t->sizearray; if (j > 0 && ttisnil(&t->array[j - 1])) { /* there is a boundary in the array part: (binary) search for it */ unsigned int i = 0; while (j - i > 1) { unsigned int m = (i j)/2; if (ttisnil(&t->array[m - 1])) j = m; else i = m; } return i; } /* else must find a boundary in hash part */ else if (isdummy(t->node)) /* hash part is empty? */ return j; /* that is easy... */ else return unbound_search(t j); } 还是先数组,数组没有后hash部分。再来看下关于hash表部分的取长度 static int unbound_search (Table *t unsigned int j) { unsigned int i = j; /* i is zero or a present index */ j ; /* find `i' and `j' such that i is present and j is not */ while (!ttisnil(luaH_getint(t j))) { i = j; j *= 2; if (j > cast(unsigned int MAX_INT)) { /* overflow? */ /* table was built with bad purposes: resort to linear search */ i = 1; while (!ttisnil(luaH_getint(t i))) i ; return i - 1; } } /* now do a binary search between them */ while (j - i > 1) { unsigned int m = (i j)/2; if (ttisnil(luaH_getint(t m))) j = m; else i = m; } return i; }

j 保证j是hash部分的第一个值,从j开始 如果j位置是有值的,那么将j扩大两倍,再检查两倍之后hash表中是否可以取到值,直到找到没有值的地方,这个值就在i 到 j这个区间中。然后再用折半查找找到 i 到 j之间找到的最后一个nil的,前面的就是它的长度了。 错略看来。luaH_getint用来取值。
const TValue luaH_getint (Table t int key)而它的声明看来 ,第二个参数是key,通过key来取value, 而外面对传入的key是 的操作 可知计算长度用来寻找的这个key一定是个整形,而且还得是连续的(不一定)。(当然这个是不深究细节实现错略看下来的分析。。。。。)。

再来验证下:

local test1 = {1 3 [4] = 4 [6] = 6 [2] = 2}
print(#test1)
打印结果: 2
也就是上面源码中,会先遍历数组部分,数组部分有就结束,没有再遍历hash表部分

local test1 = {[4] = 4 [6] = 6 [2] = 2}
print(#test1)
打印结果:0
数组之后的第一位是j 如果value是nil i 是 0 ,j 是1 返回值是0

看两个一起的:
local test1 = {[1] = 1 [2] = 2 [4] = 4 [6] = 6}
print(#test1)

local test1 = {[1] = 1 [2] = 2 [5] = 5 [6] = 6}
print(#test1)

两个的输出结果是6和2 ,而且要是将第一个打印出来 是1 2 3 4 nil 6 中间差一个就能打出来后面的,差两个就不行了 why?就是因为上面源码中得算法。

举个例子:
local test1 = {[1] = 1 [2] = 2 [3] = 3 [4] = 4 [6] = 6}
第一个while循环结束 i == 4 j == 8 通过下面的折半查找(具体细节还是拿笔算下吧。。。) 最后i == 6了

而local test1 = {[1] = 1 [2] = 2 [5] = 5 [6] = 6}
第一个while循环后 i == 2 j == 4 折半查找后 i == 2

恩 就是这样了,如果不清楚这个的话,那么在实际操作的时候,会遇到很奇怪的问题而浪费大量时间。。。。

最后local test1 = { [‘a’] = 1 [‘b’] = 2 [‘c’] = 3}
print(#test1)
打印结果: 0 key必须是整形才能用#取。

其他取数组长度形式
如果是字符串或者其他形式的,还是采用循环pairs这种形式去取为好。

三十七、身份证验证

问: 既然有身份证验证的网络接口 为什么仍需要前端验证呢?
答: 需要先过滤掉一些奇葩(长度不对 特殊字符 生日2222年13月32日) 减轻服务器的压力

--验证身份证信息 --只支持18位身份证的验证 --[[ #身份证18位编码规则:dddddd yyyymmdd xxx y #dddddd:地区码 #yyyymmdd: 出生年月日 #xxx:顺序类编码,无法确定,奇数为男,偶数为女 #y: 校验码,该位数值可通过前17位计算获得 #<p /> #18位号码加权因子为(从右到左) Wi = [ 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 1 ] #验证位 Y = [ 1 0 10 9 8 7 6 5 4 3 2 ] #校验位计算公式:Y_P = mod( ∑(Ai×Wi) 11 ) #i为身份证号码从右往左数的 2...18 位; Y_P为脚丫校验码所在校验码数组位置 参考代码: https://github.com/yujinqiu/idlint ]] local string_len = string.len local tonumber = tonumber -- // wi =2(n-1)(mod 11) local wi = { 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 1 }; -- // verify digit local vi= { '1' '0' 'X' '9' '8' '7' '6' '5' '4' '3' '2' }; local function isBirthDate(date) local year = tonumber(date:sub(1 4)) local month = tonumber(date:sub(5 6)) local day = tonumber(date:sub(7 8)) if year < 1900 or year > 2100 or month >12 or month < 1 then return false end -- //月份天数表 local month_days = { 31 28 31 30 31 30 31 31 30 31 30 31}; local bLeapYear = (year % 4 == 0 and year % 100 ~= 0) or (year % 400 == 0) if bLeapYear then month_days[2] = 29; end if day > month_days[month] or day < 1 then return false end return true end local function isAllNumberOrWithXInEnd( str ) local ret = str:match("%d X?") return ret == str end local function checkSum(idcard) -- copy from http://stackoverflow.com/questions/829063/how-to-iterate-individual-characters-in-lua-string local nums = { } local _idcard = idcard:sub(1 17) for ch in _idcard:gmatch"." do table.insert(nums tonumber(ch)) end local sum = 0 for i k in ipairs(nums) do sum = sum k * wi[i] end return vi [sum % 11 1] == idcard:sub(18 18 ) end local err_success = 0 local err_length = 1 local err_province = 2 local err_birth_date = 3 local err_code_sum = 4 local err_unknow_charactor = 5 local function verifyIDCard(idcard) if string_len(idcard) ~= 18 then return err_length end if not isAllNumberOrWithXInEnd(idcard) then return err_unknow_charactor end -- //第1-2位为省级行政区划代码,[11 65] (第一位华北区1,东北区2,华东区3,中南区4,西南区5,西北区6) local nProvince = tonumber(idcard:sub(1 2)) if( nProvince < 11 or nProvince > 65 ) then return err_province end -- //第3-4为为地级行政区划代码,第5-6位为县级行政区划代码因为经常有调整,这块就不做校验 -- //第7-10位为出生年份;//第11-12位为出生月份 //第13-14为出生日期 if not isBirthDate(idcard:sub(7 14)) then return err_birth_date end if not checkSum(idcard) then return err_code_sum end return err_success end local function UnitTest_CheckBirthDay() assert(isBirthDate('19881128') == true) assert(isBirthDate('19881328') == false) assert(isBirthDate('19881232') == false) assert(isBirthDate('19880229') == true) assert(isBirthDate('19880228') == true) assert(isBirthDate('18000228') == false) assert(isBirthDate('20000229') == true) assert(isBirthDate('21220228') == false) end local function UnitTest() print('begin UnitTest') UnitTest_CheckBirthDay() assert(verifyIDCard('411302198011276412') == err_code_sum) assert(verifyIDCard('4113021988112864x7') == err_unknow_charactor) assert(verifyIDCard('41130219881128641') == err_length) end UnitTest()三十八、逻辑运算符的优先级

^ not * / - .. > < >= <= ~= == and or

注意: and 优先级大于 or,同时出现and和or时,先执行and 比如:

A or B and C 等同于 A or (B and C)

还要注意: not 的优先级大于 == 比如:

print(1 == 2) -- false print(not 1 == 2) -- 还是false -- 都是false 我还以为是Lua或者VSCode出bug了 -- 其实是因为not优先 print(not (1 == 2)) -- true三十九、虚变量

(虚设变量/ 虚拟变量/ 名义变量/ 哑元变量/ 哑变量 叫啥玩意都行)。

t = { '迪迦' '戴拿' '蒂格' '蒂纳'} for k v in pairs(t) do print(v) end

这时 我们只需要v 而不需要k,这时 按照约定俗成 把 k 写成 _。
↓此写法表示: 我不需要理会k这个变量 即 虚变量。

t = { '迪迦' '戴拿' '蒂格' '蒂纳'} for _ v in pairs(t) do print(v) end四十、匹配字母和数字

function isMatch(str) match = string.match(str '%w ') return str == match end四十一、if not a

不用写 if a == false or a == nil then 直接写 if not a then 就好了四十二、墙裂推荐一个VS Code的插件: Rainbow Fart

你敲代码时候 她会说话 敲个if 她说: 你就是因为想太多"如果" 才找不到女朋友的 现在是晚上9点 她说: 怎么还没下班呀四十三、数组洗牌打乱

function shuffle(tbl) local n = #tbl for i = 1 n do local j = math.random(i n) if j > i then tbl[i] tbl[j] = tbl[j] tbl[i] end end end四十四、JavaBean的要求规范

  • 1、所有属性为private
  • 2、提供默认构造方法
  • 3、提供getter和setter
  • 4、实现serializable接口

这是为了向后兼容 改的时候只改方法内部就好了 便于封装重用 便于让其他程序员或者框架使用。

四十五、实现Switch

记得多看几遍这个myMetaTable干了什么。

table[4] = print('我是4') local table = { [1] = print('我是1') a = print('我是a') b = print('我是b') __default = print('我是default') } myMetaTable = { __index = function(t k) print(t == table k) return rawget(t '__default') end } setmetatable(table myMetaTable) function switch(case) return table[case] end table.c = print('我是c') switch(1) switch(4) switch(a) switch('b') switch('c') switch(d) print('卧槽 这Lua的调用顺序好乱啊') 输出: 我是4 我是1 我是a 我是b 我是default 我是c true 1 true 4 true nil true b true c true nil 卧槽 这Lua的调用顺序好乱啊四十六、实现continue

思路: 用一次性while里的if-break作为continue。

for i = 1 10 do while true do if i > 3 and i < 8 then break end print(i) break end end 输出: 1 2 3 8 9 10四十七、string.format

必须记住的: %d: 整数 %f: 浮点数 %s: 字符串。其他的不太重要 等用到的时候再查。

0.前面加加号: " " print(string.format("% d" 1234)) 输出: 1234 1.前面补0: "08d" string.format("d" 1234)) 输出: 00001234 2.截取小数 4舍5入: ".3f" string.format("%.3f" math.pi) 输出: 3.142 3.截取字符串: ".3s" string.format("%.3s" "abcdefg") 输出: abc四十八、三元表达式

(在Lua中false和nil为假 其他都是真 0也是真 {}也是真),(a and b: 如果a假 则返回a 否则返回b),(a or b: 如果a真 则返回a 否则返回b)。

C#的三元表达式ret = a ? b : c 在Lua中可以写成:

ret = a and b or c

但是 上式中b一定不能为假 若b为假 就会始终返回c。
解决: 把b放进表里 因为{false}为真 {nil}也为真。
注意: 不能把a放进表里 那样的话a恒为真 会始终返回b。
最终 严谨的写法为:

ret = (a and { b} or { c})[1]

当然 当我们确认b不可能为假时 就可以直接写: ret = a and b or c

四十九、"逻辑与"的截断机制

在C#里: a && b 先判断a是否为真 如果a为真 再判断b是否为真 b为真则返回true b为假则返回false 如果a为假 就截断了 b不看了 直接返回false 在Lua里: a and b 先判断a是否为真 直接截断! b不看了 a为假则返回a a为真则返回b 可以看出 lua比C#更省劲五十、问题:Lua的输出乱码

输出为: ‘lua‘ �����ڲ����ⲿ���Ҳ���ǿ����еij��� ���������ļ��� 解决: 改系统字体为 utf-8, 控制面板 区域设置:Bate版UTF8全球支持

lua编程基础入门教程(学习Lua碰到的问题)(7)

五十一、问题:Lua不是内部或外部命令,也不是可运行的程序或批处理文件

输出为: ‘lua‘ is not recognized as an internal or external command operable program or batch file 解决:下载Lua,配Lua的环境变量:将Lua.exe所在路径添加至系统变量的Path中五十二、判断table里有没有某元素

判断表里有没有一个value 需要遍历表 挨个判断是否相等。
判断表里有没有一个key 只需要: return t[key] ~= nil。

需要注意的是判断空表:

--这样是不行的 if a == { } --要这样: if next(a) == nil

弹出表中的下一个元素 结果它弹出来个nil 不就证明了是空表嘛。

五十三、(不)连续表的遍历

连续表(类似数组)遍历用 ipairs 非连续表(类似字典)遍历用 pairs 五十四、正则表达式

ua的正则表达式: string.gmatch(%d )五十五、取模和取余

正好前几天教二年级数学,被除数 ÷ 除数 = 商 … 余数。

local line = math.modf(9 / 4) -- 取整数 local mod = math.fmod(9 4) -- 取模 local remain = 9 % 4 -- 取余数

在数学中 取模和取余基本上说的是同一个事,在计算机中 却不大一样 (在有负号的时候)。

print('取模: ' .. math.fmod(9 4)) print('取余: ' .. 9 % 4) print('---------------') print('取模: ' .. math.fmod(-9 4)) print('取余: ' .. -9 % 4) print('---------------') print('取模: ' .. math.fmod(9 -4)) print('取余: ' .. 9 % -4) 输出: 取模: 1 取余: 1 --------------- 取模: -1 取余: 3 --------------- 取模: 1 取余: -3五十六、#汉字长度

一个汉字占3个长度。

print(#"四个汉字") 输出: 12五十七、赋值多个值

a a= 3 4 5 print(a) 输出: 3五十八、交换2个值

不需要开辟额外的temp空间 也不用巧妙的加减运算或是位运算,Lua的写法贼简单 直接 a b = b a。

a = 1 b = 2 a b = b a

交换数组的元素也可以。

arr = { 'a' 'b' 'c'} arr[1] arr[3] = arr[3] arr[1] for i v in pairs(arr) do print(i .. v) end 输出: 1c 2b 3a五十九、返回多个值

function fun() return 1 2 3 end print("额" fun()) print(fun() "额") -- 因为fun不是最后一个 所以只返回一个值 print((fun())) -- 强制仅返回一个值 输出: 额 1 2 3 1 额 1六十、方法后面不加小括号

a = aaa{ "a" "b"}

看到这个写法我当时蒙了 这是什么写法? 表? 不对啊 它为什么不报错呢?哦 原来aaa是个方法啊。

function aaa(t) print(t[1]) end --因为传参是table, 所以可省略小括号 --正常写法为: a = aaa({ 2 3}) --省略写法为: a = aaa { 2 3}六十一、按位运算

a~b 按位异或 ~a 按位取反六十二、// 运算 取商

不知道为什么 网上查不到这个操作符号"//",我猜是取商运算。

print(5 // 2) print(5.0 // 2) print(5 // 2.0) 输出: 2 2.0 2.0 注意: 当被除数或除数为浮点数时 结果也是浮点数

猜您喜欢: