1、标准库

math库

  1. ----------------三角函数库----------------
  2. --都是以弧度为单位
  3. math.sin
  4. math.cos
  5. math.tan
  6. math.asin
  7. math.acos
  8. math.pi = 3.1415926
  9. math.deg --弧度 ->
  10. math.rad --度 -> 弧度
  11. ----------------幂指函数库----------------
  12. math.exp
  13. math.log
  14. math.log10
  15. ----------------舍入函数----------------
  16. math.floor
  17. math.ceil
  18. math.max
  19. math.min
  20. ----------------随机数函数----------------
  21. math.random() -- [0, 1)
  22. math.random(n) -- [1, n]
  23. math.random(a, b) -- [a, b]
  24. math.randomseed(seed) --随机数发生器,seednumber,相同seed,随机序列相同。

table库

  1. ----------------数组操作----------------
  2. table.setn(t, len) -- 设置数组t长度为lent.n = len
  3. -- 这个功能是为了兼容旧版本
  4. table.getn(t) -- 数组长度t.n,如果n不存在,则遍历。
  5. table.insert(t, pos, v) -- tpos位置插入v,后面元素后移
  6. table.insert(t, v) -- t的尾部插入
  7. table.remove(t, pos, v) -- 删除pos位置元素,后面元素前移
  8. table.remove(t) -- 删除最后一个
  9. -- 几百个元素的插入删除,效率没有问题。
  10. table.sort(t, function(left, right) --对数组t排序,
  11. -- left 数组元素
  12. -- right left相邻右边的元素
  13. -- return true: left right 不交换位置,反之交换位置。
  14. -- return a < b: 默认排序,如为number,则从小到大排序。
  15. end)
  16. local a = { 1, 2, 3, nil, 5, 6}
  17. print(table.getn(a)) --> 3
  18. -------------按指定key排序方法,遍历数组-------------
  19. local a = {
  20. luaH_set = 10,
  21. luaH_get = 24,
  22. luaH_present = 48,
  23. }
  24. local function pairsByKeys(t, key_order)
  25. local keys = {}
  26. for k in pairs(t) do table.insert(keys, k) end
  27. table.sort(keys, key_order)
  28. local var_control = 0
  29. return function(t)
  30. var_control = var_control + 1
  31. if keys[var_control] ~= nil then
  32. return keys[var_control], t[keys[var_control]]
  33. else
  34. return nil
  35. end
  36. end, t
  37. end
  38. for k in pairsByKeys(t) do
  39. print(k) --> luaH_getluaH_presentluaH_set
  40. end

string库

字符串无法被切割。

常见函数

  1. -- 位置规则以下通用:
  2. -- 位置<0,则从尾部往头部计算位置,
  3. -- -1最后一个字符位置,-2倒数第二的位置
  4. string.len(str) --字符串长度
  5. string.rep(str, n) --str重复n次的串
  6. string.lower(str) --切换成小写
  7. string.upper(str) --切换成大写
  8. string.sub(str, i, j) --返回一个str串的子串,位置:i~j
  9. --i,j<0,从尾部计数,-1是最后一个位置。
  10. --j:默认-1
  11. string.sub(str, i, -1) -- 等价
  12. string.sub(str, i) -- 等价
  13. string.char(...) -- 返回字符串:由每个数字转成字符拼接而成。
  14. string.byte(str, i) -- pos位置字符转成整数,pos默认1
  15. string.byte(str, 1) -- 等价
  16. string.byte(str) -- 等价
  17. string.format(str, ...) --和C printf几乎一样
  18. --------------例子--------------
  19. local s = string.rep("a", 2^20) --1MB的串,测试需要
  20. string.sub(s, 2, -2) -- 注意s并没有改变
  21. s = string.sub(s, 2, -2) -- s才是截取的字符串,新手很容易出错
  22. --%x:十六进制,%d:十进制,%o:八进制,%f:浮点数
  23. string.format("pi = %.4f", PI) --> pi = 3.1416
  24. d = 5; m = 11; y = 1990
  25. string.format("%02d/%02d/%04d", d, m, y) --> 05/11/1990
  26. tag, title = "h1", "a title"
  27. string.format("<%s>%s</%s>", tag, title, tag) --> <h1>a title</h1>

模式匹配函数

string.find(字符串查找)
string.gsub(全局字符串替换)
string.gfind(全局字符串查找)
string.gmatch(返回查找到字符串的迭代器)

string.find

  1. -- 查找str中匹配pattern的字串起始位置和捕获(如果有)
  2. -- str: 目标字符串
  3. -- pattern: 字符串、模式
  4. -- start: strstart位置开始搜索,可以用于查找全部。
  5. -- plain: bool值,false表示使用模式匹配,true表示普通的字符串匹配。默认false
  6. -- a, b: 匹配字符串的首尾位置
  7. -- ...: 返回捕获值,如果有。
  8. a, b, ... = string.find(str, pattern, start, plain)
  9. local s = "am+df"
  10. print(string.find(s, "m+", 1, false)) -- 2 2
  11. print(string.find(s, "m+", 1, true)) -- 2 3
  12. print(string.find(s, "(m+)", 1, false)) -- 2 2 m
  13. print(string.find(s, "((m+))", 1)) -- 2 2 m m
  14. -- 先最外层捕获
  15. print(string.find(s, "(((m+)))", 1)) -- 2 2 m m m
  16. -- ()当前字符串匹配进行到的位置
  17. print(string.find(s, "()(m+)()", 1)) -- 2 2 2 m 3

string.gsub

  1. -- 查找str中匹配pattern的所有字符串,并用replace产生的字串替换
  2. -- str: 目标字符串
  3. -- pattern: 字符串、模式
  4. -- replace: 字符串时,这个好理解
  5. -- table时,key为第一个捕获的串,没有显示捕获,就是整个匹配到的,没有查询到不做替换
  6. -- 函数时,function(...)end,...为所有的捕获(按顺序),返回值必须是数字或字符串
  7. -- time: 最大替换次数
  8. -- s: 替换后的字符串(副本)
  9. -- count: 替换次数
  10. s, count = string.gsub(str, pattern, replace, time)
  11. local s = "am+dmf"
  12. --%d表示第d个捕获,1<d<=9,%0表示匹配到的整个串。
  13. print(string.gsub(s, "()(m+)", "%1")) -- a2+d5f 2
  14. print(string.gsub(s, "()(m+)", "%2")) -- am+dmf 2
  15. print(string.gsub(s, "()(m+)", "%3")) -- error: invalid capture index
  16. print(string.gsub(s, "()(m+)", "%0%0%0")) -- ammm+dmmmf 2
  17. function f1(...)
  18. print(...) -- 2 m
  19. -- 5 m
  20. return "hh"
  21. end
  22. function f2()
  23. return { 123 }
  24. end
  25. print(string.gsub(s, "()(m+)", f1)) -- ahh+dhhf 2
  26. print(string.gsub(s, "()(m+)", f2)) -- error : invalid replacement value ( a table )

string.match

  1. -- 查找str中匹配pattern的第一个捕获,默认是整个pattern匹配的
  2. -- str: 目标字符串
  3. -- pattern: 字符串、模式
  4. -- start: 匹配起始位置
  5. -- capture: 第一个捕获
  6. capture = string.match(str, pattern, start)

string.gmatch

老版本叫string.gfind

  1. -- 返回str匹配pattern的迭代器,一般用于遍历匹配全部。
  2. -- str: 目标字符串
  3. -- pattern: 字符串、模式
  4. -- iter: 一个迭代器
  5. iter = string.gmatch(str, pattern)
  6. ------------------------例子------------------------
  7. t, s = {},"from=world, to=Lua"
  8. for k, v in string.gmatch(s, "(%w+)=(%w+)") do
  9.  t[ k ]=v
  10. end
  11. for 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中的模式匹配效率是不错的,尽可能的更明确的模式描述。一个限制宽松的模式比限制严格的模式可能慢很多,永远不要写一个以 ‘-‘ 开头或者结尾的模式,因为它将匹配空串,一个包含 ‘.*’ 的模式是需要注意的,因为这个结构可能会比你预算的扩展的要多。

常见的模式匹配

  1. -- 查找一个文本中行字符大于70个的行,也就是匹配一个非换行符之前有70个字符的行。
  2. pattern = string.gsub("[^\n]", 70) .. "[^\n]*"
  3. -- 字符串s1转化为s2,而不关心其中的特殊字符
  4. s1 = string.gsub(s1, "(%W)", "%%%1")
  5. s2 = string.gsub(s2, "%%", "%%%%")

捕获Captures

一种机制,使用模式串的一部分匹配目标串的一部分。将你想捕获的模式用()括起来,就指定了一个capture。

  1. pair = "name = Anna"
  2. a, b, key, value = string.find(pair, "(%a+)%s*=%s*(%a+)")
  3. print(key, value) --> name Anna
  4. -- ab是匹配字符串的索引下标

2、I/O库

注意一个小问题,DOS和UNIX系统的文本文件格式不同,DOS是回车换行符\r\n,UNIX是换行符\n,请注意替换区分。

简单I/O模式

非句柄式操作文件。

  1. -- 设置当前标准输入(stdin),如文件,默认文本模式
  2. -- filename_or_handle: 可以是文件名或者完全I/O模式的文件句柄
  3. io.input(filename_or_handle)
  4. io.output(a) --标准输出,同上用法。
  5. io.flush() --清空输出缓冲,即所有write操作立即生效。
  6. print --始终使用stdout
  7. io.read(arg) --从标准输入读入一行
  8. io.read("*all") --从当前位置,读取整个文件,刚好在文件尾或空文件,返回空串
  9. io.read("*line") --从当前位置,读取下一行,没有换行符,没有返回nil
  10. io.read() --同上等价
  11. io.lines() --逐行读取迭代器,用于泛型for
  12. io.read("*number") --从当前位置,读取1个可识别的数字,返回number,找不到返回nil
  13. --文件内数字字符用空格等隔开,效率大增
  14. io.read("*number","*number") --读取2个可识别的数字
  15. io.read("*number","*number","*number") --读取3个可识别的数字
  16. io.read(10) --读取最多10个字符(字节)
  17. --可以看到这些参数可以组合的
  18. --8KB为单元读取,避免切割行
  19. --lines: 8KB字节内容
  20. --rest: 如何切割了行,就返回行剩余部分
  21. --linesrest拼接起来就是行结尾的内容。
  22. local lines, rest = io.read(2^13, "*line")
  23. io.write(...) --向标准输出输出
  24. io.write(string.format(...)) -- 常用方法
  25. ---------------例子---------------
  26. a, b, c = "a", "b", "c"
  27. io.write(a .. b .. c) --杜绝此类写法
  28. io.write(a, b, c) --以此代替
  29. local cell_size = 2^13 -- 高效复制文件
  30. while true do
  31. local block = io.read(cell_size)
  32. if not block then break end
  33. io.write(block)
  34. end

完全I/O模式

通过句柄操作文件,类似C的FILE*

  1. -- 获取filename的句柄,俗称打开文件
  2. -- 注意可能失败返回nil,做好考虑
  3. -- filename : 文件名
  4. -- mode : 打开模式。
  5. -- r:读模式,默认模式
  6. -- w:写模式,覆盖
  7. -- a:追加模式
  8. -- b:二进制模式,可附加在后面
  9. -- return : handle,文件句柄,打开成功
  10. -- errorinfo,打开失败信息,handlenil
  11. local handle = io.open(filename, mode)
  12. -- 调整当前文件的存取位置,文件就像一个线性表,存取位置就是“栅栏”
  13. -- whence: offset的偏移方式,默认为"cur"
  14. -- set:从文件头便宜offset个字节
  15. -- cur:从当前位置offset个字节
  16. -- end:从文件尾往前偏移offset个字节
  17. -- offset: 偏移字节数,默认0
  18. -- return: 新的存取位置,
  19. local pos = handle.seek(whence, offset)
  20. io.stderr --预定义句柄,可直接使用,别特么自己close
  21. io.stdin --预定义句柄
  22. io.stdout --预定义句柄
  23. local f = assert(io.open(filename, mode)) --常见使用方式
  24. f:read("*all") --操作方式和简单I/O一样,但是注意用冒号:
  25. f:close() --切记别忘了关闭

3、os库

文件管理,系统时钟等等与操作系统相关信息,只提供ANSI C标准内的,没有目录管理,套接字。

  1. os.clock() --当前CPU时钟秒数,用来计算执行时间
  2. os.exit() --程序终止执行
  3. os.getenv(envname) --等到环境变量,如:
  4. os.getenv("HOME") -- /home/lua,没有返回nil
  5. os.execute(cmd) -- MS-DOS命令,和Csystem函数等价
  6. --设置程序所在区域
  7. --category: 特性,默认all
  8. -- collate排序,控制字符的排列顺序
  9. -- monetary货币
  10. -- numeric数字,控制数字的格式
  11. -- time控制时间的格式
  12. -- all包含以上所以特性
  13. os.setlocale(locale, category)
  14. os.setlocale("ISO-8859-1", "collate")
  15. -- a=nil时,返回当前距离某个特定时间的秒数
  16. -- a~=nil时,返回距离时间表a的秒数
  17. -- a:时间表,格式如下:
  18. -- {
  19. -- year=1970, month=1,
  20. -- day=1, hour=0,
  21. -- sec=1, isdst
  22. -- }
  23. -- isdst:是否夏令时间,一般都停用了
  24. local seconds = os.time(a)
  25. -- os.time互为“反函数”
  26. -- 返回秒数seconds对应的时间表
  27. -- format: 时间表格式
  28. -- *t,返回下面temp格式
  29. -- %*,根据标记为填充,格式化输出,看下面例子
  30. -- seconds: 距离某一时间的秒数,默认当前时间秒数
  31. -- return: 返回时间表
  32. local temp = os.date(format, seconds)
  33. --temp = {
  34. -- year = 1998,
  35. -- month = 9,
  36. -- day = 16,
  37. -- yday = 259, --一年中的第几天,11日为1
  38. -- wday = 4, --星期天为1
  39. -- hour = 23,
  40. -- min = 48,
  41. -- sec = 10,
  42. -- isdst = false
  43. --}
  44. print(os.date("today is %A, in %B")) --> today is Tuesday, in May
  45. print(os.date("%x", 906000490)) --> 09/16/1998
  46. -- 全部的标记位如下:
  47. %a abbreviated weekday name (e.g., Wed)
  48. %A full weekday name (e.g., Wednesday)
  49. %b abbreviated month name (e.g., Sep)
  50. %B full month name (e.g., September)
  51. %c date and time (e.g., 09/16/98 23:48:10)
  52. %d day of the month (16) [01-31]
  53. %H hour, using a 24-hour clock (23) [00-23]
  54. %I hour, using a 12-hour clock (11) [01-12]
  55. %M minute (48) [00-59]
  56. %m month (09) [01-12]
  57. %p either "am" or "pm" (pm)
  58. %S second (10) [00-61]
  59. %w weekday (3) [0-6 = Sunday-Saturday]
  60. %x date (e.g., 09/16/98)
  61. %X time (e.g., 23:48:10)
  62. %Y full year (1998)
  63. %y two-digit year (98) [00-99]
  64. %% the character '%'

4、debug库

提供设计调试器的接口,C API实现。
表debug包含全部函数。分两类函数:

自省函数:introspective,获取运行程序当前状态,如活动函数栈、当前执行代码的行号、本地变量的名和值。
跟踪函数:hooks,到达某一事件时,回调。

栈级别(stack level):
调用debug库的函数级别为1,设为func
调用func的函数级别为2,以此类推

自省:debug.info

  1. -- arg: number: 返回n级栈的活动函数的信息数据,n过大,返回nil
  2. -- function: 函数变量。
  3. -- conf: string,需要返回哪些信息的配置。mask字符串,如"nfl"
  4. -- "n",返回namenamewhat
  5. -- "f",返回func
  6. -- "S",返回source, short_src, what, and linedefined
  7. -- "l",返回currentline
  8. -- "u",返回nup
  9. -- return: 函数信息表
  10. local info = debug.getinfo(n, conf)
  11. info = {
  12. -- source 函数被定义的地方,字符串(loadstring)或者文件名
  13. -- short_src 记录一些有用的错误信息, 最多60byte
  14. -- linedefined 函数在source中被定义的行号
  15. -- what 标明函数类型。
  16. -- lua: lua函数
  17. -- C: C函数
  18. -- main: chunk
  19. -- name 函数的合理名称。
  20. -- namewhat 上一个字段代表的含义。"global""local""method""field"
  21. -- 或者 ""(空字符串)。空字符串意味着Lua没有找到这个函数名。
  22. -- nups 函数的upvalues的个数。
  23. -- func 函数本身;详细情况看后面。
  24. -- currentline getinfo(n)时,才有的字段。
  25. }
  26. -- func_or_stacklvlC函数时,what, name, namewhat可用。
  27. debug.getinfo(1) -- 返回当前所在函数的栈信息
  28. debug.getinfo(0) -- debug.getinfo本身
  29. debug.traceback()
  30. -- 获取活动栈中活动函数的局部变量
  31. -- stack_lvl: 栈级别,1:调用debug.getlocal所在函数。
  32. -- var: 要获取的变量索引,按声明顺序,见下例
  33. -- var_name: 变量名称
  34. -- var_val: 变量值
  35. local var_name, var_val = debug.getlocal(stack_lvl, var)
  36. -- 修改活动栈中活动函数的局部变量
  37. -- stack_lvl: 栈级别,1:调用debug.getlocal所在函数。
  38. -- var: 要获取的变量索引,按声明顺序,见下例
  39. -- new_val: 变量新值
  40. -- var_name: 变量名称
  41. local var_name = debug.setlocal(stack_lvl, var, new_val)
  42. -- 获取/设置函数的upvalue
  43. -- func: 函数,为啥没有栈级别了?函数不在运行太也有闭包
  44. -- upval_index: upvalue的索引。按被引用顺序
  45. -- new_val: upvalue新值
  46. -- var_name: upvalue名称
  47. local upval_name = debug.getupvalue(func, upval_index)
  48. local upval_name = debug.setupvalue(func, upval_index, new_val)
  49. -----------------debug.getlocal 例子-----------------
  50. function foo (a,b) -- a:索引为1b:索引为2
  51. local x -- 索引为3
  52. do local c = a - b end
  53. local a = 1 -- 索引为4,存储的是索引值
  54. while true do
  55. local name, value = debug.getlocal(1, a)
  56. if not name then break end
  57. print(name, value)
  58. a = a + 1
  59. end
  60. end
  61. foo(10, 20)
  62. --结果为:
  63. --a 10
  64. --b 20
  65. --x nil
  66. --a 4
  67. -----------------debug.getupvalue 例子-----------------
  68. function getvarvalue (name) --查找变量名为name的变量值
  69. local value, found
  70. local i = 1
  71. while true do
  72. local n, v = debug.getlocal(2, i) --1、先找局部变量
  73. if not n then break end
  74. if n == name then
  75. value = v
  76. found = true
  77. end
  78. i = i + 1
  79. end
  80. if found then return value end
  81. -- try upvalues
  82. local func = debug.getinfo(2).func
  83. i = 1
  84. while true do
  85. local n, v = debug.getupvalue(func, i) -- 2、再找upvalue是否存在
  86. if not n then break end
  87. if n == name then return v end
  88. i = i + 1
  89. end
  90. -- not found; get global
  91. return getfenv(func)[name] --3、再看调用getvarvalue的函数环境中是否有这个全局变量。
  92. end

hook函数

  1. --当触发event事件,回调callback,参数arg
  2. --callback: 回调函数function(event, arg)end
  3. --event: 触发回调事件,mask字符串
  4. -- call/c: 调用函数时
  5. -- return/r: 函数返回时
  6. -- line/l: 执行代码新行时
  7. -- count: 运行arg条指令时,
  8. debug.sethook(callback, event, arg) -- 注册
  9. debug.sethook() --注销
  10. -----------------例子-----------------
  11. function trace (event, line)
  12. local s = debug.getinfo(2).short_src --文件信息等
  13. print(s .. ":" .. line)
  14. end
  15. debug.sethook(trace, "l")

Profiling 统计

  1. ------------记录每个函数被调用次数------------
  2. local function hook ()
  3. local f = debug.getinfo(2, "f").func --获得调用hook的函数chunk
  4. if Counters[f] == nil then --第一次调用函数f
  5. Counters[f] = 1
  6. Names[f] = debug.getinfo(2, "Sn") --key:函数,value:函数信息表
  7. else
  8. Counters[f] = Counters[f] + 1 --调用次数+1
  9. end
  10. end
  11. function getname (func) --函数的函数名
  12. local n = Names[func]
  13. if n.what == "C" then --是C函数
  14. return n.name
  15. end
  16. local loc = string.format("[%s]:%s",
  17. n.short_src, n.linedefined) --[函数所在文件名]函数所在行数
  18. if n.namewhat ~= "" then --找到函数名
  19. return string.format("%s (%s)", loc, n.name) --[文件名]行数 函数名
  20. else --没找到函数名
  21. return string.format("%s", loc) --行数
  22. end
  23. end
  24. -- prompt> lua profiler main-prog
  25. local f = assert(loadfile(arg[1])) --main-progchunk
  26. debug.sethook(hook, "c") --有函数调用时触发
  27. f() --运行main-prog
  28. debug.sethook() -- 关闭hook
  29. for func, count in pairs(Counters) do
  30. print(getname(func), count) --函数基本信息,函数调用次数
  31. end
  32. -----------------输出示例-----------------
  33. [markov.lua]:4 884723
  34. write 10000
  35. [markov.lua]:0 (f) 1
  36. read 31103
  37. sub 884722
  38. [markov.lua]:1 (allwords) 1
  39. [markov.lua]:20 (prefix) 894723
  40. find 915824
  41. [markov.lua]:26 (insert) 884723
  42. random 10000
  43. sethook 1
  44. insert 884723