1、标准库
math库
----------------三角函数库------------------都是以弧度为单位math.sinmath.cosmath.tanmath.asinmath.acosmath.pi = 3.1415926math.deg --弧度 -> 度math.rad --度 -> 弧度----------------幂指函数库----------------math.expmath.logmath.log10----------------舍入函数----------------math.floormath.ceilmath.maxmath.min----------------随机数函数----------------math.random() -- [0, 1)math.random(n) -- [1, n]math.random(a, b) -- [a, b]math.randomseed(seed) --随机数发生器,seed:number,相同seed,随机序列相同。
table库
----------------数组操作----------------table.setn(t, len) -- 设置数组t长度为len,t.n = len-- 这个功能是为了兼容旧版本table.getn(t) -- 数组长度t.n,如果n不存在,则遍历。table.insert(t, pos, v) -- 在t的pos位置插入v,后面元素后移table.insert(t, v) -- 在t的尾部插入table.remove(t, pos, v) -- 删除pos位置元素,后面元素前移table.remove(t) -- 删除最后一个-- 几百个元素的插入删除,效率没有问题。table.sort(t, function(left, right) --对数组t排序,-- left: 数组元素-- right: left相邻右边的元素-- return true: left 和 right 不交换位置,反之交换位置。-- return a < b: 默认排序,如为number,则从小到大排序。end)local a = { 1, 2, 3, nil, 5, 6}print(table.getn(a)) --> 3-------------按指定key排序方法,遍历数组-------------local a = {luaH_set = 10,luaH_get = 24,luaH_present = 48,}local function pairsByKeys(t, key_order)local keys = {}for k in pairs(t) do table.insert(keys, k) endtable.sort(keys, key_order)local var_control = 0return function(t)var_control = var_control + 1if keys[var_control] ~= nil thenreturn keys[var_control], t[keys[var_control]]elsereturn nilendend, tendfor k in pairsByKeys(t) doprint(k) --> luaH_get、luaH_present、luaH_setend
string库
常见函数
-- 位置规则以下通用:-- 位置<0,则从尾部往头部计算位置,-- -1最后一个字符位置,-2倒数第二的位置string.len(str) --字符串长度string.rep(str, n) --str重复n次的串string.lower(str) --切换成小写string.upper(str) --切换成大写string.sub(str, i, j) --返回一个str串的子串,位置:i~j--i,j<0,从尾部计数,-1是最后一个位置。--j:默认-1,string.sub(str, i, -1) -- 等价string.sub(str, i) -- 等价string.char(...) -- 返回字符串:由每个数字转成字符拼接而成。string.byte(str, i) -- pos位置字符转成整数,pos默认1string.byte(str, 1) -- 等价string.byte(str) -- 等价string.format(str, ...) --和C printf几乎一样--------------例子--------------local s = string.rep("a", 2^20) --1MB的串,测试需要string.sub(s, 2, -2) -- 注意s并没有改变s = string.sub(s, 2, -2) -- s才是截取的字符串,新手很容易出错--%x:十六进制,%d:十进制,%o:八进制,%f:浮点数string.format("pi = %.4f", PI) --> pi = 3.1416d = 5; m = 11; y = 1990string.format("%02d/%02d/%04d", d, m, y) --> 05/11/1990tag, title = "h1", "a title"string.format("<%s>%s</%s>", tag, title, tag) --> <h1>a title</h1>
模式匹配函数
string.find(字符串查找)
string.gsub(全局字符串替换)
string.gfind(全局字符串查找)
string.gmatch(返回查找到字符串的迭代器)
string.find
-- 查找str中匹配pattern的字串起始位置和捕获(如果有)-- str: 目标字符串-- pattern: 字符串、模式-- start: 从str的start位置开始搜索,可以用于查找全部。-- plain: bool值,false表示使用模式匹配,true表示普通的字符串匹配。默认false-- a, b: 匹配字符串的首尾位置-- ...: 返回捕获值,如果有。a, b, ... = string.find(str, pattern, start, plain)local s = "am+df"print(string.find(s, "m+", 1, false)) -- 2 2print(string.find(s, "m+", 1, true)) -- 2 3print(string.find(s, "(m+)", 1, false)) -- 2 2 mprint(string.find(s, "((m+))", 1)) -- 2 2 m m-- 先最外层捕获print(string.find(s, "(((m+)))", 1)) -- 2 2 m m m-- ()当前字符串匹配进行到的位置print(string.find(s, "()(m+)()", 1)) -- 2 2 2 m 3
string.gsub
-- 查找str中匹配pattern的所有字符串,并用replace产生的字串替换-- str: 目标字符串-- pattern: 字符串、模式-- replace: 字符串时,这个好理解-- table时,key为第一个捕获的串,没有显示捕获,就是整个匹配到的,没有查询到不做替换-- 函数时,function(...)end,...为所有的捕获(按顺序),返回值必须是数字或字符串-- time: 最大替换次数-- s: 替换后的字符串(副本)-- count: 替换次数s, count = string.gsub(str, pattern, replace, time)local s = "am+dmf"--%d表示第d个捕获,1<d<=9,%0表示匹配到的整个串。print(string.gsub(s, "()(m+)", "%1")) -- a2+d5f 2print(string.gsub(s, "()(m+)", "%2")) -- am+dmf 2print(string.gsub(s, "()(m+)", "%3")) -- error: invalid capture indexprint(string.gsub(s, "()(m+)", "%0%0%0")) -- ammm+dmmmf 2function f1(...)print(...) -- 2 m-- 5 mreturn "hh"endfunction f2()return { 123 }endprint(string.gsub(s, "()(m+)", f1)) -- ahh+dhhf 2print(string.gsub(s, "()(m+)", f2)) -- error : invalid replacement value ( a table )
string.match
-- 查找str中匹配pattern的第一个捕获,默认是整个pattern匹配的-- str: 目标字符串-- pattern: 字符串、模式-- start: 匹配起始位置-- capture: 第一个捕获capture = string.match(str, pattern, start)
string.gmatch
老版本叫string.gfind
-- 返回str匹配pattern的迭代器,一般用于遍历匹配全部。-- str: 目标字符串-- pattern: 字符串、模式-- iter: 一个迭代器iter = string.gmatch(str, pattern)------------------------例子------------------------t, s = {},"from=world, to=Lua"for k, v in string.gmatch(s, "(%w+)=(%w+)") dot[ k ]=vendfor k, v in pairs(t) do print(k, v) end
模式匹配pattern
出于程序大小考虑,Lua采用的不是通用POSIX规范的正则表达式(regexp)。
字符类
字符类指可以匹配一个特定字符集合内任何字符的模式项,下面是Lua支持的所有字符类:
| . | 任意字符 | %a | 字母 |
|---|---|---|---|
| %c | 控制字符 | %d | 数字 |
| %p | 标点字符 | %l | 小写字母 |
| %s | 空白符 | %u | 大写字母 |
| %w | 字母和数字 | %z | 代表0的字符 |
| 大写是小写的补集 |
特殊含义字符
( ) . % + - * ? [ ^ $
%后面跟任意一个非字母和数字的字符,都代表了这个字符本身,包括上面那些特殊字符以及任何标点符号都可以用这个方式来表达。
[…]方括号,自定义字符类,[%w_]匹配字母数字和下划线,[01]匹配二进制数字,可以使用范围表示字符集合,如[0-9]等价于%d,%x等价于[0-9a-fA-F]
[^…],^在方括号中表示补集。’[^0-7]’ 匹配任何不是八进制数字的字符。
以 ‘^’ 开头的模式只匹配目标串的开始部分。
以 ‘$’ 结尾的模式只匹配目标串的结尾部分。
‘%b’ 用来匹配对称的字符。如’%b()’ 匹配以 ‘(‘ 开始,以 ‘)’ 结束的字符串,包括()。常见的有’%b()’ ,’%b[]’,’%b%{%}’ 和 ‘%b<>’
尽量使用%l表示小写字母更简单更高效,而不是[a-z],字符类依赖于本地环境。
修饰符
- 匹配前一字符1次或多次,最长匹配
* 匹配前一字符0次或多次
- 匹配前一字符0次或多次,最短匹配
? 匹配前一字符0次或1次
一般情况下,Lua中的模式匹配效率是不错的,尽可能的更明确的模式描述。一个限制宽松的模式比限制严格的模式可能慢很多,永远不要写一个以 ‘-‘ 开头或者结尾的模式,因为它将匹配空串,一个包含 ‘.*’ 的模式是需要注意的,因为这个结构可能会比你预算的扩展的要多。
常见的模式匹配
-- 查找一个文本中行字符大于70个的行,也就是匹配一个非换行符之前有70个字符的行。pattern = string.gsub("[^\n]", 70) .. "[^\n]*"-- 字符串s1转化为s2,而不关心其中的特殊字符s1 = string.gsub(s1, "(%W)", "%%%1")s2 = string.gsub(s2, "%%", "%%%%")
捕获Captures
一种机制,使用模式串的一部分匹配目标串的一部分。将你想捕获的模式用()括起来,就指定了一个capture。
pair = "name = Anna"a, b, key, value = string.find(pair, "(%a+)%s*=%s*(%a+)")print(key, value) --> name Anna-- a、b是匹配字符串的索引下标
2、I/O库
注意一个小问题,DOS和UNIX系统的文本文件格式不同,DOS是回车换行符\r\n,UNIX是换行符\n,请注意替换区分。
简单I/O模式
非句柄式操作文件。
-- 设置当前标准输入(stdin),如文件,默认文本模式-- filename_or_handle: 可以是文件名或者完全I/O模式的文件句柄io.input(filename_or_handle)io.output(a) --标准输出,同上用法。io.flush() --清空输出缓冲,即所有write操作立即生效。print --始终使用stdoutio.read(arg) --从标准输入读入一行io.read("*all") --从当前位置,读取整个文件,刚好在文件尾或空文件,返回空串io.read("*line") --从当前位置,读取下一行,没有换行符,没有返回nilio.read() --同上等价io.lines() --逐行读取迭代器,用于泛型forio.read("*number") --从当前位置,读取1个可识别的数字,返回number,找不到返回nil--文件内数字字符用空格等隔开,效率大增io.read("*number","*number") --读取2个可识别的数字io.read("*number","*number","*number") --读取3个可识别的数字io.read(10) --读取最多10个字符(字节)--可以看到这些参数可以组合的--8KB为单元读取,避免切割行--lines: 8KB字节内容--rest: 如何切割了行,就返回行剩余部分--lines,rest拼接起来就是行结尾的内容。local lines, rest = io.read(2^13, "*line")io.write(...) --向标准输出输出io.write(string.format(...)) -- 常用方法---------------例子---------------a, b, c = "a", "b", "c"io.write(a .. b .. c) --杜绝此类写法io.write(a, b, c) --以此代替local cell_size = 2^13 -- 高效复制文件while true dolocal block = io.read(cell_size)if not block then break endio.write(block)end
完全I/O模式
通过句柄操作文件,类似C的FILE*
-- 获取filename的句柄,俗称打开文件-- 注意可能失败返回nil,做好考虑-- filename : 文件名-- mode : 打开模式。-- r:读模式,默认模式-- w:写模式,覆盖-- a:追加模式-- b:二进制模式,可附加在后面-- return : handle,文件句柄,打开成功-- errorinfo,打开失败信息,handle为nillocal handle = io.open(filename, mode)-- 调整当前文件的存取位置,文件就像一个线性表,存取位置就是“栅栏”-- whence: offset的偏移方式,默认为"cur"-- set:从文件头便宜offset个字节-- cur:从当前位置offset个字节-- end:从文件尾往前偏移offset个字节-- offset: 偏移字节数,默认0-- return: 新的存取位置,local pos = handle.seek(whence, offset)io.stderr --预定义句柄,可直接使用,别特么自己close了io.stdin --预定义句柄io.stdout --预定义句柄local f = assert(io.open(filename, mode)) --常见使用方式f:read("*all") --操作方式和简单I/O一样,但是注意用冒号:f:close() --切记别忘了关闭
3、os库
文件管理,系统时钟等等与操作系统相关信息,只提供ANSI C标准内的,没有目录管理,套接字。
os.clock() --当前CPU时钟秒数,用来计算执行时间os.exit() --程序终止执行os.getenv(envname) --等到环境变量,如:os.getenv("HOME") -- /home/lua,没有返回nilos.execute(cmd) -- 如MS-DOS命令,和C的system函数等价--设置程序所在区域--category: 特性,默认all。-- collate排序,控制字符的排列顺序-- monetary货币-- numeric数字,控制数字的格式-- time控制时间的格式-- all包含以上所以特性os.setlocale(locale, category)os.setlocale("ISO-8859-1", "collate")-- a=nil时,返回当前距离某个特定时间的秒数-- a~=nil时,返回距离时间表a的秒数-- a:时间表,格式如下:-- {-- year=1970, month=1,-- day=1, hour=0,-- sec=1, isdst-- }-- isdst:是否夏令时间,一般都停用了local seconds = os.time(a)-- 和os.time互为“反函数”-- 返回秒数seconds对应的时间表-- format: 时间表格式-- *t,返回下面temp格式-- %*,根据标记为填充,格式化输出,看下面例子-- seconds: 距离某一时间的秒数,默认当前时间秒数-- return: 返回时间表local temp = os.date(format, seconds)--temp = {-- year = 1998,-- month = 9,-- day = 16,-- yday = 259, --一年中的第几天,1月1日为1-- wday = 4, --星期天为1-- hour = 23,-- min = 48,-- sec = 10,-- isdst = false--}print(os.date("today is %A, in %B")) --> today is Tuesday, in Mayprint(os.date("%x", 906000490)) --> 09/16/1998-- 全部的标记位如下:%a abbreviated weekday name (e.g., Wed)%A full weekday name (e.g., Wednesday)%b abbreviated month name (e.g., Sep)%B full month name (e.g., September)%c date and time (e.g., 09/16/98 23:48:10)%d day of the month (16) [01-31]%H hour, using a 24-hour clock (23) [00-23]%I hour, using a 12-hour clock (11) [01-12]%M minute (48) [00-59]%m month (09) [01-12]%p either "am" or "pm" (pm)%S second (10) [00-61]%w weekday (3) [0-6 = Sunday-Saturday]%x date (e.g., 09/16/98)%X time (e.g., 23:48:10)%Y full year (1998)%y two-digit year (98) [00-99]%% the character '%'
4、debug库
提供设计调试器的接口,C API实现。
表debug包含全部函数。分两类函数:
自省函数:introspective,获取运行程序当前状态,如活动函数栈、当前执行代码的行号、本地变量的名和值。
跟踪函数:hooks,到达某一事件时,回调。
栈级别(stack level):
调用debug库的函数级别为1,设为func
调用func的函数级别为2,以此类推
自省:debug.info
-- arg: number: 返回n级栈的活动函数的信息数据,n过大,返回nil-- function: 函数变量。-- conf: string,需要返回哪些信息的配置。mask字符串,如"nfl"-- "n",返回name、namewhat-- "f",返回func-- "S",返回source, short_src, what, and linedefined-- "l",返回currentline-- "u",返回nup-- return: 函数信息表local info = debug.getinfo(n, conf)info = {-- source 函数被定义的地方,字符串(loadstring)或者文件名-- short_src 记录一些有用的错误信息, 最多60byte-- linedefined 函数在source中被定义的行号-- what 标明函数类型。-- lua: lua函数-- C: C函数-- main: 主chunk。-- name 函数的合理名称。-- namewhat 上一个字段代表的含义。"global"、"local"、"method"、"field",-- 或者 ""(空字符串)。空字符串意味着Lua没有找到这个函数名。-- nups 函数的upvalues的个数。-- func 函数本身;详细情况看后面。-- currentline getinfo(n)时,才有的字段。}-- func_or_stacklvl是C函数时,what, name, namewhat可用。debug.getinfo(1) -- 返回当前所在函数的栈信息debug.getinfo(0) -- debug.getinfo本身debug.traceback()-- 获取活动栈中活动函数的局部变量-- stack_lvl: 栈级别,1:调用debug.getlocal所在函数。-- var: 要获取的变量索引,按声明顺序,见下例-- var_name: 变量名称-- var_val: 变量值local var_name, var_val = debug.getlocal(stack_lvl, var)-- 修改活动栈中活动函数的局部变量-- stack_lvl: 栈级别,1:调用debug.getlocal所在函数。-- var: 要获取的变量索引,按声明顺序,见下例-- new_val: 变量新值-- var_name: 变量名称local var_name = debug.setlocal(stack_lvl, var, new_val)-- 获取/设置函数的upvalue-- func: 函数,为啥没有栈级别了?函数不在运行太也有闭包-- upval_index: upvalue的索引。按被引用顺序-- new_val: upvalue新值-- var_name: upvalue名称local upval_name = debug.getupvalue(func, upval_index)local upval_name = debug.setupvalue(func, upval_index, new_val)-----------------debug.getlocal 例子-----------------function foo (a,b) -- a:索引为1,b:索引为2local x -- 索引为3do local c = a - b endlocal a = 1 -- 索引为4,存储的是索引值while true dolocal name, value = debug.getlocal(1, a)if not name then break endprint(name, value)a = a + 1endendfoo(10, 20)--结果为:--a 10--b 20--x nil--a 4-----------------debug.getupvalue 例子-----------------function getvarvalue (name) --查找变量名为name的变量值local value, foundlocal i = 1while true dolocal n, v = debug.getlocal(2, i) --1、先找局部变量if not n then break endif n == name thenvalue = vfound = trueendi = i + 1endif found then return value end-- try upvalueslocal func = debug.getinfo(2).funci = 1while true dolocal n, v = debug.getupvalue(func, i) -- 2、再找upvalue是否存在if not n then break endif n == name then return v endi = i + 1end-- not found; get globalreturn getfenv(func)[name] --3、再看调用getvarvalue的函数环境中是否有这个全局变量。end
hook函数
--当触发event事件,回调callback,参数arg--callback: 回调函数function(event, arg)end--event: 触发回调事件,mask字符串-- call/c: 调用函数时-- return/r: 函数返回时-- line/l: 执行代码新行时-- count: 运行arg条指令时,debug.sethook(callback, event, arg) -- 注册debug.sethook() --注销-----------------例子-----------------function trace (event, line)local s = debug.getinfo(2).short_src --文件信息等print(s .. ":" .. line)enddebug.sethook(trace, "l")
Profiling 统计
------------记录每个函数被调用次数------------local function hook ()local f = debug.getinfo(2, "f").func --获得调用hook的函数chunkif Counters[f] == nil then --第一次调用函数fCounters[f] = 1Names[f] = debug.getinfo(2, "Sn") --key:函数,value:函数信息表elseCounters[f] = Counters[f] + 1 --调用次数+1endendfunction getname (func) --函数的函数名local n = Names[func]if n.what == "C" then --是C函数return n.nameendlocal loc = string.format("[%s]:%s",n.short_src, n.linedefined) --[函数所在文件名]函数所在行数if n.namewhat ~= "" then --找到函数名return string.format("%s (%s)", loc, n.name) --[文件名]行数 函数名else --没找到函数名return string.format("%s", loc) --行数endend-- prompt> lua profiler main-proglocal f = assert(loadfile(arg[1])) --main-prog的chunkdebug.sethook(hook, "c") --有函数调用时触发f() --运行main-progdebug.sethook() -- 关闭hookfor func, count in pairs(Counters) doprint(getname(func), count) --函数基本信息,函数调用次数end-----------------输出示例-----------------[markov.lua]:4 884723write 10000[markov.lua]:0 (f) 1read 31103sub 884722[markov.lua]:1 (allwords) 1[markov.lua]:20 (prefix) 894723find 915824[markov.lua]:26 (insert) 884723random 10000sethook 1insert 884723
