文章目录

  • 一、遍历字典是无序的
  • 二、Lua的遍历和C#不同
  • 三、同名传参和同名字段
  • 四、传参是引用传递
  • 五、rawget()和rawset()
  • 六、在Windows上安装Lua
    • 1.get a binary
    • 2.选择自己电脑的版本
    • 3.解压文件,(存放文件地址文件夹名全部不要出现中文最佳)
    • 4.修改环境变量
    • 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()
  • 二十八、lua特殊写法
  • 二十九、变量名
  • 三十、今天星期几
  • 三十一、os.time(): 秒
  • 三十二、裆下日期转成表, 再把表转成秒
  • 三十三、看身份证满18没有
  • 三十四、Lua没有"继承"的弊端
  • 三十五、取字符串的长度
  • 三十六、#号
  • 三十七、身份证验证
  • 三十八、逻辑运算符的优先级
  • 三十九、虚变量
  • 四十、匹配字母和数字
  • 四十一、if not a
  • 四十二、墙裂推荐一个VS Code的插件: Rainbow Fart
  • 四十三、数组洗牌打乱
  • 四十四、JavaBean的要求规范
  • 四十五、实现Switch
  • 四十六、实现continue
  • 四十七、string.format
  • 四十八、三元表达式
  • 四十九、"逻辑与"的截断机制
  • 五十、问题:Lua的输出乱码
  • 五十一、问题:Lua不是内部或外部命令,也不是可运行的程序或批处理文件
  • 五十二、判断table里有没有某元素
  • 五十三、(不)连续表的遍历
  • 五十四、正则表达式
  • 五十五、取模和取余
  • 五十六、#汉字长度
  • 五十七、赋值多个值
  • 五十八、交换2个值
  • 五十九、返回多个值
  • 六十、方法后面不加小括号
  • 六十一、按位运算
  • 六十二、// 运算, 取商

一、遍历字典是无序的

t = {}
t.a = '1'
t.b = '2'
t.c = '3'
t.d = '4'
for i,v in pairs(t) doprint(v)
end-- 每次输出都是乱序的!!!

二、Lua的遍历和C#不同

function Cnt()print('执行Cnt方法')return 3
end
for i = 1, Cnt() doprint(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。
置空attr.name, 会同时置空ultraman.attr.name。

如下↓:

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

改变attr, 不会同时改变ultraman.attr。
置空attr, 不会同时置空ultraman.attr。

如下↓:

ultraman = {attr = {name = '奥特曼'}}
attr = ultraman.attrattr = {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

2.选择自己电脑的版本

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

4.修改环境变量

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

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

七、把数值转成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 / num2local t1, t2 = math.modf(quotient)-- 去掉数字后面的.0if t2 == 0 thenreturn t1elsereturn quotientend
endprint(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 dolet = 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
cdecde
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)
enda = 2
-- 不执行
fun = function(b)fooo(a, b)
end
-- 执行, 输出2,3
fun(3)

二十、死循环

这样写就是死循环↓:

for i = 1, i + 10 doprint(i)
end

正确写法↓:

local endNum = i + 10
for i = 1, endNum doprint(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(...)-- 用表{...}来接收, 将会丢失传参中的nillocal arg = {...}for k, v in pairs(arg) doprint(v)end
end
Foo1('奥特曼', nil)输出:
奥特曼
----------------------------------function Foo2(...)-- 用table.pack(...)来接收, 会给一个'n'作为indexlocal arg = table.pack(...)for i = 1, arg.n doprint(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) doindex = index + 1v.name = karray[index] = v
end
table.sort(array,function(a, b)return a.order < b.orderend
)
for i = 1, #array dolocal 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相等, 则判断条件2return a.arg2 < b.arg2endreturn a.arg1 < b.arg1end
)
for i = 1, #tab doprint(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 thenreturn nilendlocal result = {}for match in (str .. delimiter):gmatch('(.-)' .. delimiter) dotable.insert(result, match)endreturn result
end-- 测试
local str = "1::3";
local list = string.split(str, ":");
for key, value in pairs(list) doprint(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) doprint(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 thenreturn dt.year - year - 1elseif month == dt.month and day >= dt.day thenreturn dt.year - year - 1elsereturn dt.year - yearendendreturn 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)
打印结果: 5local 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)
打印结果: 6for 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 thenreturn falseend-- //月份天数表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  thenmonth_days[2] = 29;endif day > month_days[month] or day < 1 thenreturn falseendreturn true
endlocal function isAllNumberOrWithXInEnd( str )local ret = str:match("%d+X?") return ret == str
endlocal function checkSum(idcard)-- copy from http://stackoverflow.com/questions/829063/how-to-iterate-individual-characters-in-lua-stringlocal nums = {}local _idcard = idcard:sub(1,17)for ch in _idcard:gmatch"." dotable.insert(nums,tonumber(ch))endlocal sum = 0for i,k in ipairs(nums) dosum = sum + k * wi[i]endreturn vi [sum % 11+1] == idcard:sub(18,18 )
endlocal 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 = 5local function verifyIDCard(idcard)if string_len(idcard) ~= 18 thenreturn err_lengthendif not isAllNumberOrWithXInEnd(idcard) thenreturn err_unknow_charactorend-- //第1-2位为省级行政区划代码,[11, 65] (第一位华北区1,东北区2,华东区3,中南区4,西南区5,西北区6)local nProvince = tonumber(idcard:sub(1, 2))if( nProvince < 11 or nProvince > 65 ) thenreturn err_provinceend-- //第3-4为为地级行政区划代码,第5-6位为县级行政区划代码因为经常有调整,这块就不做校验-- //第7-10位为出生年份;//第11-12位为出生月份 //第13-14为出生日期if not isBirthDate(idcard:sub(7,14)) thenreturn err_birth_dateendif not checkSum(idcard) thenreturn err_code_sumendreturn err_success
endlocal 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)endlocal function UnitTest()print('begin UnitTest')UnitTest_CheckBirthDay()assert(verifyIDCard('411302198011276412') == err_code_sum)assert(verifyIDCard('4113021988112864x7') == err_unknow_charactor)assert(verifyIDCard('41130219881128641') == err_length)
endUnitTest()

三十八、逻辑运算符的优先级

^
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) doprint(v)
end

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

t = {'迪迦', '戴拿', '蒂格', '蒂纳'}
for _, v in pairs(t) doprint(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 = #tblfor i = 1, n dolocal j = math.random(i, n)if j > i thentbl[i], tbl[j] = tbl[j], tbl[i]endend
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]
endtable.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 dowhile true doif i > 3 and i < 8 thenbreakendprint(i)breakend
end
输出:
1 2 3 8 9 10

四十七、string.format

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

0.前面加加号: "+"
print(string.format("%+d", 1234))
输出: +12341.前面补0: "08d"
string.format("%08d", 1234))
输出: 000012342.截取小数, 4舍5入: ".3f"
string.format("%.3f", math.pi)
输出: 3.1423.截取字符串: ".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‘ 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) doprint(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
注意: 当被除数或除数为浮点数时, 结果也是浮点数

学习Lua碰到的问题、踩坑记录相关推荐

  1. cesium给地图添加比例尺学习踩坑记录

    cesium给地图添加比例尺学习踩坑记录 因项目需要在cesium地图中展示比例尺,本来应该是很简单的事,但却碰到了一个引用文件的坑,特此记录: *1.引用依赖文件 相信需要用到cesium比例尺组件 ...

  2. 【学习记录】QT5界面设计的踩坑记录

    学习记录:QT5 界面设计的踩坑记录 前言 一.Qlabel显示视频与图片 1. 图片显示 1.1 显示格式 1.2 label随界面缩放 1.3 界面刷新 2. 视频显示 二.常见控件的StyleS ...

  3. AirSim学习和踩坑记录(不定时更新)

    版权声明:本文为博主原创文章,遵循Creative Commons - Attribution-ShareAlike 4.0 International - CC BY-SA 4.0版权协议,转载请附 ...

  4. MAC-XXL_JOB学习踩坑记录-Failed to create parent directories for [/data/applogs/xxl-job/xxl-job-admin.log

    MAC-XXL_JOB学习踩坑记录 源码下载地址 启动报错 源码下载地址 ①.GitHub:https://github.com/xuxueli/xxl-job ②.码云:https://gitee. ...

  5. Slam学习笔记——ROS踩坑记录

    Slam学习笔记--ROS踩坑记录 1. 安装 2. ROS文件系统 2.1 工作区 2.2 包package 2.2.1 包的操作 2.2.2 描述文件package.xml 2.3 节点node ...

  6. 双系统Ubuntu22.04深度学习环境配置与踩坑记录

    双系统Ubuntu22.04深度学习环境配置踩坑记录 前言 目录 相关版本 主要参考教程 Ubuntu安装 Nvidia和CUDA安装 踩坑经历 官网安装所遇问题 cuDNN安装 Anaconda安装 ...

  7. mybatis学习与踩坑记录

    mybatis resultmap高级映射 应用场景:如果sql查询的列名和pojo的属性名不一致,可以使用resultMap将列名和pojo的属性名作一个对应关系,就可以映射成功了.(如果返回值为i ...

  8. 【踩坑记录】仿真环境使用小车进行Cartographer 3D Slam(深度摄像头)

    [运行背景] ROS1 20.04 noetic 安装cartographer请看: [安装学习]安装Cartographer ROS(noetic)_Howe_xixi的博客-CSDN博客网上使用n ...

  9. ROS noetic 安装编译Cartographer踩坑记录

    ROS noetic 安装编译Cartographer踩坑记录 安装编译工具 sudo apt-get update sudo apt-get install -y python-wstool pyt ...

  10. 【踩坑记录】实体机器人运行Cartographer 3D Slam(深度摄像头)--未解决

    [运行背景] ROS1.0  20.04 noetic 机器人:NXRobo SPARK-T 安装cartographer请看: [安装学习]安装Cartographer ROS(noetic)_Ho ...

最新文章

  1. android的shadowRadius属性说明
  2. Python基础教程:列表解析
  3. 项目常用第三方库 Swift版
  4. [js高手之路]this知多少
  5. python继承方式是基于原型吗_基于原型与基于类的继承
  6. 七步从Angular.JS菜鸟到专家(2):Scopes
  7. chage 用户密码管理
  8. 信息传递(NOIP2015提高组Day1T2)
  9. 给还是不给?又一个国家要求苹果必须为iPhone 12提供充电器
  10. golang 单协程和多协程的性能测试
  11. 中国农历2013,2014 (zz.IS2120@BG57IV3)
  12. 2492 上帝造题的七分钟 2
  13. 0618----Shell(二)
  14. 如何使用fiddler抓取APP接口
  15. HyperLynx(三)传输线类型及相关设置
  16. 如何将App程序发布到苹果App Store
  17. Java bean 复制克隆工具
  18. CC00034.bigdatajava——|Java方法封装.V16|——|Java.v16|费氏数列.v02|递推实现|
  19. java高级架构师年薪,深度集成!
  20. intelx79服务器芯片组,流言终结者!Intel X79规格全面介绍

热门文章

  1. java版超级玛丽游戏
  2. 有选择的忽略PyCharm 3的PEP8语言风格警告提示信息
  3. mapper找不到报错:Field xxxMapper in xxx required a bean of type 'xxxMapper' that could not be found
  4. Java面试之Java基础5——面向对象的三大特性之封装、继承和多态
  5. 为了让机器听懂“长篇大论”,阿里工程师构建了新模型
  6. jsp左侧菜单栏_HTML页面左侧菜单栏切换实现右侧主体内容改变
  7. 【C语言学习】————操作符、关键字
  8. 紫罗兰计算机音乐,【Animenz】紫罗兰永恒花园ed みちしるべ
  9. macOs Ventura 13自动开机关机设置教程(命令行)
  10. Android欢迎页面以及引导页面