这里只介绍和插件编写比较有关的几个函数. 详细的Lua手册请参照Lua Reference Manual 5.1.
 

table函数库

一部分的table函数只对其数组部分产生影响, 而另一部分则对整个table均产生影响. 下面会分开说明. 


table.concat(table, sep,  start, end)

concat是concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的分隔符(sep)隔开.

除了table外, 其他的参数都不是必须的, 分隔符的默认值是空字符, start的默认值是1, end的默认值是数组部分的总长.

sep, start, end这三个参数是顺序读入的, 所以虽然它们都不是必须参数, 但如果要指定靠后的参数, 必须同时指定前面的参数.

> tbl = {"alpha", "beta", "gamma"}
> print(table.concat(tbl, ":"))
alpha:beta:gamma
> print(table.concat(tbl, nil, 1, 2))
alphabeta
> print(table.concat(tbl, "\n", 2, 3))
beta
gamma


table.insert(table, pos, value)

table.insert()函数在table的数组部分指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾.

> tbl = {"alpha", "beta", "gamma"}
> table.insert(tbl, "delta")
> table.insert(tbl, "epsilon")
> print(table.concat(tbl, ", ")
alpha, beta, gamma, delta, epsilon
> table.insert(tbl, 3, "zeta")
> print(table.concat(tbl, ", ")
alpha, beta, zeta, gamma, delta, epsilon


table.maxn(table)

table.maxn()函数返回指定table中所有正数key值中最大的key值. 如果不存在key值为正数的元素, 则返回0. 此函数不限于table的数组部分.

> tbl = {[1] = "a", [2] = "b", [3] = "c", [26] = "z"}
> print(#tbl)
3               -- 因为26和之前的数字不连续, 所以不算在数组部分内
> print(table.maxn(tbl))
26
> tbl[91.32] = true
> print(table.maxn(tbl))
91.32


table.remove(table, pos)

table.remove()函数删除并返回table数组部分位于pos位置的元素. 其后的元素会被前移. pos参数可选, 默认为table长度, 即从最后一个元素删起.


table.sort(table, comp)

table.sort()函数对给定的table进行升序排序.

> tbl = {"alpha", "beta", "gamma", "delta"}
> table.sort(tbl)
> print(table.concat(tbl, ", "))
alpha, beta, delta, gamma

comp是一个可选的参数, 此参数是一个外部函数, 可以用来自定义sort函数的排序标准.

此函数应满足以下条件: 接受两个参数(依次为a, b), 并返回一个布尔型的值, 当a应该排在b前面时, 返回true, 反之返回false.

例如, 当我们需要降序排序时, 可以这样写:

> sortFunc = function(a, b) return b < a end
> table.sort(tbl, sortFunc)
> print(table.concat(tbl, ", "))
gamma, delta, beta, alpha

用类似的原理还可以写出更加复杂的排序函数. 例如, 有一个table存有工会三名成员的姓名及等级信息:

guild = {}

table.insert(guild, {
 name = "Cladhaire",
 class = "Rogue",
 level = 70,
})

table.insert(guild, {
 name = "Sagart",
 class = "Priest",
 level = 70,
})

table.insert(guild, {
 name = "Mallaithe",
 class = "Warlock",
 level = 40,
})


对这个table进行排序时, 应用以下的规则: 按等级升序排序, 在等级相同时, 按姓名升序排序.

可以写出这样的排序函数:

function sortLevelNameAsc(a, b)
 if a.level == b.level then
  return a.name < b.name
 else
  return a.level < b.level
 end
end

测试功能如下:

> table.sort(guild, sortLevelNameAsc)
> for idx, value in ipairs(guild) do print(idx, value.name) end
1, Mallaithe
2, Cladhaire
3, Sagart

 

数学函数库

以下是一些常用的Lua标准库的数学成员, 按字母顺序排列.

函数                                                功能

math.abs(x)                                    返回x的绝对值
math.ceil(x)                                     返回不小于x的最小整数
math.deg(x)                                    将弧度制的x转化为角度
math.exp(x)                                    返回e的x次方
math.floor(x)                                   返回不大于x的最大整数
math.fmod(x, y)                               或x % y, 返回x除以y的余数
math.log(x)                                     返回x的自然对数值
math.log10(x)                                  返回x的常用对数值
math.max(x, y, z, ...)                       返回参数列表中的最大值
math.min(x, y, z, ...)                        返回参数列表中的最小值
math.modf(x)                                  返回两个值, 依次为x的整数和小数部分
math.pi                                           圆周率常量
math.pow(x, y)                                计算并返回x的y次方
math.rad(x)                                     将角度制的x转化为弧度
math.random(m, n)                          产生随机数, 参数可选并影响范围: 无参数时为[0, 1), 
                                                      单参数时为[1, m], 双参数时为[m, n]
math.randomseed(x)                        重设随机种子
math.sqrt(x)                                    开平方根运算

 

字符串函数库

以下是一些常用的Lua标准库的字符串工具: 

函数                                                功能

string.len(s)                                    返回s的长度
string.lower(s)                                 返回一个s的副本, 其中的所有大写字母均转换为小写
string.rep(s, n)                                返回一个字符串, 由n个s头尾相接而成
string.reverse(s)                              返回一个由s倒转构成的字符串
string.sub(s, i, j)                              返回s的子字符串, 从i开始, 到j(可缺, 默认为末尾)结束
                  i, j可以是负值, 此时从字符串结尾开始向前计算
                  例如: Hello的-3~-1代表llo子字符串
string.upper(s)                                 返回一个s的副本, 其中的所有小写字母均转换为大写

 

字符串格式化

Lua提供了string.format()函数来生成具有特定格式的字符串, 函数的第一个参数是格式(formatstring), 之后是对应格式中每个代号的各种数据. 由于格式字符串的存在, 使得产生的长字符串可读性大大提高了. 这个函数的格式很像C语言中的printf().

格式字符串可能包含以下的转义码:

%c - 接受一个数字, 并将其转化为ASCII码表中对应的字符
%d, %i - 接受一个数字并将其转化为有符号的整数格式
%o - 接受一个数字并将其转化为八进制数格式
%u - 接受一个数字并将其转化为无符号整数格式
%x - 接受一个数字并将其转化为十六进制数格式, 使用小写字母
%X - 接受一个数字并将其转化为十六进制数格式, 使用大写字母
%e - 接受一个数字并将其转化为科学记数法格式, 使用小写字母e
%E - 接受一个数字并将其转化为科学记数法格式, 使用大写字母E
%f - 接受一个数字并将其转化为浮点数格式
%g(%G) - 接受一个数字并将其转化为%e(%E, 对应%G)及%f中较短的一种格式
%q - 接受一个字符串并将其转化为可安全被Lua编译器读入的格式
%s - 接受一个字符串并按照给定的参数格式化该字符串

为进一步细化格式, 可以在%号后添加参数. 参数将以如下的顺序读入:

(1) 符号: 一个+号表示其后的数字转义符将让正数显示正号. 默认情况下只有负数显示符号.
(2) 占位符: 一个0, 在后面指定了字串宽度时占位用. 不填时的默认占位符是空格.
(3) 对齐标识: 在指定了字串宽度时, 默认为右对齐, 增加-号可以改为左对齐.
(4) 宽度数值
(5) 小数位数/字串裁切: 在宽度数值后增加的小数部分n, 若后接f(浮点数转义符, 如%6.3f)则设定该浮点数的小数只保留n位, 若后接s(字符串转义符, 如%5.3s)则设定该字符串只显示前n位.

在这些参数的后面则是上述所列的转义码类型(c, d, i, f, ...).

以下是一些例子:

string.format("%%c: %c", 83)            输出S
string.format("%+d", 17.0)              输出+17
string.format("%05d", 17)               输出00017
string.format("%o", 17)                 输出21
string.format("%u", 3.14)               输出3
string.format("%x", 13)                 输出d
string.format("%X", 13)                 输出D
string.format("%e", 1000)               输出1.000000e+03
string.format("%E", 1000)               输出1.000000E+03
string.format("%6.3f", 13)              输出13.000
string.format("%q", "One\nTwo")         输出"One\
                                          Two"
string.format("%s", "monkey")           输出monkey
string.format("%10s", "monkey")         输出    monkey
string.format("%5.3s", "monkey")        输出  mon

在魔兽世界中还有另一个string.format()参数, 允许不按后面的列出顺序读取参数. 在这种情况下, 使用参数的排位+$符号来指定特定的参数.
(此语句在非WoW的Lua编译器中将不能正确运作. 请使用WoWLua或Lua511WoW)

例如:

> print(string.format("%2$d, %1$d, %d", 13, 17))
17, 13, 13

如果设定了$参数, 其必须紧接在%符号之后, 并且所有的后续参数(在这里指13, 17)都必须被访问; 换言之如果有3个参数, 不能只使用1$和3$. 可以混用含有$和不含$的转义符; 不含$的转义符将自动从参数列表的头部开始获取数据.

$参数在实现本地化中非常方便. 在不同的语言中, 特定的名词可能会以不同顺序出现. 使用带有$参数的格式字符串, 可以使不同语言版本的客户端共用相同的参数列表.

例如下面这句游戏提示:

Cladhaire's Shadow Word: Pain is removed.

在德语版客户端中是这样写的:

'Shadow Word: Pain' von Cladhaire wurde entfernt.

在英文版中技能(暗言术·痛)出现在角色名称(Cladhaire)之后, 但在德语版中顺序正相反. 如果参数列表中角色名称是排在技能名称之前, 可以为不同的客户端分别写出如下的格式字符串:

英文版: %s's %s is removed.
德文版: '%2$s' von %1$s wurde entfernt.

这样只要向string.format()传入不同的格式字符串即可, 不需重写具有不同参数次序的语句.

 

字符串配对

书写插件经常会遇到的一个问题是: 如何处理游戏提供的文本并从中配对获取所需的信息. Lua提供了一系列的函数, 这些函数可以根据给定的配对表达式, 和给定的字符串配对, 并处理成功配对的部分.

配对表达式支持以下的字符类:

单个字符(除^$()%.[]*+-?外): 与该字符自身配对
.(点): 与任何字符配对
%a: 与任何字母配对
%c: 与任何控制符配对(例如\n)
%d: 与任何数字配对
%l: 与任何小写字母配对
%p: 与任何标点(punctuation)配对
%s: 与空白字符配对
%u: 与任何大写字母配对
%w: 与任何字母/数字配对
%x: 与任何十六进制数配对
%z: 与任何代表0的字符配对
%x(此处x是非字母非数字字符): 与字符x配对. 主要用来处理表达式中有功能的字符(^$()%.[]*+-?)的配对问题, 例如%%与%配对
[数个字符类]: 与任何[]中包含的字符类配对. 例如[%w_]与任何字母/数字, 或下划线符号(_)配对
[^数个字符类]: 与任何包含在[]中的字符类配对. 例如[^%s]与任何非空白字符配对

(还有一个转义码是%f. %f被称作Frontier Pattern, 因为一些原因没有被写入Lua的标准文档中. 有兴趣的朋友可以看lua-users wiki: Frontier Pattern)

当上述的字符类用大写书写时, 表示与此字符类的任何字符配对. 例如, %S表示与任何非空白字符配对.

配对表达式是由上述字符类代号加上特定选项构成的, 这些特定选项包括:

不加任何选项(例如"%a"): 与单个该类字符配对
后接*号(例如"%a*"): 与0个或更多该类字符配对. 只与给定字符串中符合要求的最长子串配对.
后接+号(例如"%a+"): 与1个或更多该类字符配对. 只与给定字符串中符合要求的最长子串配对.
后接+号(例如"%a-"): 与0个或更多该类字符配对. 只与给定字符串中符合要求的最短子串配对.
后接?号(例如"%a?"): 与0个或1个该类字符配对.

配对表达式还可包含以下两个成员:

%bxy: 其中x, y是字符. 与x开始, y结束, 并且x, y在字符串中平衡配对的字符串配对.
平衡配对表示: 设一初始值为零的计数器, 从给定字符串左侧至右侧逐个读取字符, 每读取一个x, 计数器+1, 每读取一个y, 计数器-1, 那么最后一个y恰好是第一个使计数器归零的y.
也可以说, 在%bxy成功配对的字符串中, 找不到更短的子字符串使其满足%bxy配对.
%n: 其中n是1~9的数字. 与捕获(见下文)的第n个配对字串配对.

例如: 给定字串"abc ABC 123 !@# \n \000 %"

配对表达式                                    配对结果

%a                          a b c A B C
%a*                         abc ABC
%a+                         abc ABC
%a-%s                       abc ABC
%a?                         a b c A B C
%ba3                        abc ABC 123

在配对表达式中还可以添加锚点和捕获标记.

锚点包括^和$符号, ^表示字符串起始处, $表示字符串结束处. 例如^MYADDON:.+表示以MYADDON:开头的字符串. 

出现在配对表达式中的成对的圆括号表示捕获(capture)标记. 每一对圆括号中的表达式成功配对的字符串都会被保存下来, 并且可以用%n获取(参见前文). 由于圆括号可以嵌套, 因此圆括号的编号顺序是以左括号为准的, 按左括号的出现先后顺序编号. 例如配对表达式"(a*(.)%w(%s*))"中, a*(.)%w(%s*)会被存为1号捕捉结果, .和%s*则分别是2号、3号捕捉结果.

以下是一些混合应用各种配对表达式成员的例子:

表达式               配对结果

%S+                与原字串所有非空白成员配对(即被空格隔开的每个部分)
^MYADDON:(.)       与所有MYADDON:开头的字符串配对, 并且捕获其后的部分
(%d+%.?%d*)        与所有含有或不含有小数部分的数字配对, 并捕获整个数字
(%w+)=(%S+)        与所有左侧由数字字母组成, 右侧由无空格字串组成的等式配对, 
                   并分别捕获等式的两侧.
%b''               与所有单引号内的字符串配对(包括单引号本身)
%S+$               与原字串的最后一个非空白成员配对

利用配对表达式的主要有以下几个函数: string.gmatch(str, pattern), string.gsub(str, pattern, repl, n), string.match(str, pattern, init), string.find(str, pattern, init, plain). 为简化书写, 也可以用之前在Lua的面向对象提过的方式直接通过字串自身调用这些函数(e.g. str:gmatch(pattern)).

string.gmatch(str, pattern)

之前已经提过了, 这是一个返回迭代器的函数. 实际的用例如下:

s = "hello world from Lua"
for w in string.gmatch(s, "%a+") do
 print(w)
end

这里是一个捕获并将配对字符分别存到不同变量的例子:

t = {}
s = "from=world, to=Lua"
for k, v in string.gmatch(s, "(%w+)=(%w+)") do
 t[k]=v
end
for k, v in pairs(t) do
 print(k, v)
end


string.gsub(str, pattern, repl, n)

string.gsub()函数根据给定的配对表达式对源字符串str进行配对, 同时返回源字符串的一个副本, 该副本中成功配对的所有子字符串都将被替换. 函数还将返回成功配对的次数.

实际的替换行为由repl参数的类型决定:

当repl为字符串时, 所有成功配对的子字符串均会被替换成指定的repl字串.
当repl为table时, 对每个成功配对的子字符串, 函数均会试图寻找以其为key值的table中的元素, 并返回该元素. 如果该配对包含任何捕获信息, 则以编号为1号的捕获作为key值进行查找.
当repl为函数时, 每个成功配对的子字符串均会作为参数被传入到该函数中去.
在repl是table或函数时, 如果该table或函数返回了字串或数字的值, 这个值依然会被用于替换副本字串中的配对子字串. 如果该table/函数返回的值为空, 将不发生替换.

n参数可选, 当它被指定时, string.gsub()函数只对源字符串中的前n个成功配对的成员进行操作.

以下是几个例子:

> print(string.gsub("hello world", "(%w+)", "%1 %1"))
hello hello world world 2

> print(string.gsub("hello Lua", "(%w+)%s*(&w+)", "%2 %1"))
Lua hello 1

> string.gsub("hello world", "%w+", print)
hello world 2

> lookupTable = {["hello"] = "hola", ["world"] = "mundo"}
> print(string.gsub("hello world", "(%w+)", lookupTable))
hola mundo 2


string.match(str, pattern, init)

string.match()只寻找源字串str中的第一个配对. 参数init可选, 指定搜寻过程的起点, 默认为1.

在成功配对时, 函数将返回配对表达式中的所有捕获结果; 如果没有设置捕获标记, 则返回整个配对字符串. 当没有成功的配对时, 返回nil.


string.find(str, pattern, init, plain)

string.find()寻找源字串str中的第一个成功的配对, 并返回配对子字符串的起点和终点位置. 若没有成功的配对, 则返回nil. 参数init可选, 指定搜寻过程的起点, 默认为1, 可以是负数; plain参数可选, 是个布尔值, 默认为false, 如果指定为true, 则pattern被视作普通字串(plain string), 在进行查找时, 所有其中的转义符和功能文字全部视作普通文本. 注意如果指定plain, 也必须同时指定init.

如果在配对表达式中设置了捕获标记, 函数将在返回两个位置数值后继续返回捕获结果.

 

魔兽世界对Lua新增的函数

以下函数是魔兽世界的插件界面额外增加的. 普通的Lua编译器可能不支持这些函数.

strsplit(sep, str)

strsplit()函数按给定的分隔符sep分割源字符串str并依序返回分割所得的每个部分. 等同于string.split(sep, str).

> print(strsplit(":", "foo:bar:blah"))
foo bar blah
> print(string.split(" ", "This is a string"))
This is a string

strjoin(sep, ...)

strjoin()函数将后续参数列表的所有字串依次连接起来, 并以分隔符sep两两隔开. 等同于string.join(sep, ...).

> print(strjoin(" ", "This", "is", "a", "string"))
This is a string
> print(string.join(", ", "alpha", "beta", "gamma"))
alpha, beta, gamma

strconcat(...)

strconcat()连接参数列表中的所有字符串, 并返回连接结果. 等同于string.concat(...).

> print(strconcat("This", "is", "a", "string"))
Thisisastring

getglobal(name)

获取名字为name的全局变量的值并返回该值. 在魔兽世界的界面编程中, 广泛地用于处理父框架和子框架共存时的变量问题.

setglobal(name, value)

将名为name的全局变量的值设为value. 同样是在默认魔兽界面中被广泛应用的函数.

debugstack(start, count1, count2)

调试用函数. 三个参数均是可省略的.

start: 指定堆栈深度, 追踪过程将从这里开始(默认为1)
count1: 指定达到栈顶时函数返回的值(默认为12)
count2: 指定达到栈底时函数返回的值(默认为10)

此函数只能在魔兽世界中正常工作. 普通的Lua中有其他用于追踪堆栈内容的方法.

 

函数别名

在WoW中, 大量常用的库函数均拥有别名, 以简化书写. 以下是所有别名及其对应的函数

别名                  函数                        别名                  函数

abs          math.abs         tan          math.tan
acos         math.acos        format       string.format
asin         math.asin        gmatch       string.gmatch
atan         math.atan        gsub         string.gsub
atan2        math.atan2       strbyte      string.byte
ceil         math.ceil        strchar      string.char
cos          math.cos         strfind      string.find
deg          math.deg         strlen       string.len
exp          math.exp         strlower     string.lower
floor        math.floor       strmatch     string.match
frexp        math.frexp       strrep       string.rep
ldexp        math.ldexp       strrev       string.reverse
log          math.log         strsub       string.sub
max          math.max         strupper     string.upper
min          math.min         foreach      table.foreach
mod          math.fmod        foreachi     table.foreachi
rad          math.rad         getn         table.getn
random       math.random      sort         table.sort
randomseed   math.randomseed  tinsert      table.insert
sin          math.sin         tremove      table.remove
sqrt         math.sqrt