Extension:Scribunto/Lua参考手册
此手册记载Lua 的文档,用于MediaWiki的Scribunto 扩展。 部分内容(英文原文)取自Lua 5.1参考手册(翻译时参考了Lua参考手册的中文翻译),其许可协议为MIT许可证。
此页面记载的是最新版本的Scribunto扩展的文档。某些功能可能尚未部署。 |
介绍
入门
在已启用Scribunto的MediaWiki wiki上,以Module:
前缀为标题创建一个页面,例如“Module:Bananas”。
进入该新页面,复制下列文本:
local p = {} --p代表包(package)
function p.hello( frame )
return "Hello, world!"
end
return p
將其保存,然後在另一个非模块的页面(例如在沙盒页面)上写入:
{{#invoke:Bananas|hello}}
除了你应该把「Bananas」替换成你对模块的称呼這件事略過不計,这個将會调用从该模块导出的“hello”函数。{{#invoke:Bananas|hello}}
将被替换为该函数返回的文本,在本例中是“Hello, world!”。
从模板的上下文中调用Lua代码,一般来说,是个好主意。 这意味着,从调用页面的角度来看,语法、模板逻辑是透過Lua还是透過wikitext來实现,這兩者是无关的。 它也避免了在wiki的内容命名空间中引入额外的复杂语法。
模块结构
模块本身必须返回一个包含有能被{{#invoke:}}
调用的函数的Lua表格(table)。
一般来说,如上所示,一个局部变量被声明为持有一个表格,函数被添加到这个表格中,然後该表格在模块代码的結尾處被返回。
任何一個没有加到这个表格中的函数,无论是局部还是全局,都不能被{{#invoke:}}
访问,但是全局变量可能会被其他使用require()
加载的模块访问。
一般来说,將所有的函数和变量都声明為局部的,對模块來說是一种好的风格。
從维基文本中访问参数
由{{#invoke:}}
调用的函数将被传递一个單一参数,那就是一个框架对象(frame object)。为了访问传递给{{#invoke:}}
的那個参数,代码通常会使用该框架对象的args
表格。也可以通过使用frame:getParent()
和访问该框架的args
来访问传递给包含{{#invoke:}}
的模板的参数。
这个框架对象也被用来访问wikitext分析器的上下文特定功能,例如调用分析器函数,展开模板、以及展开任意wikitext字符串。
返回的文本
模块函数通常返回单个的字符串;无论返回什么值都会通过tostring()转换,然后连接在一起。这个字符串就是转化成维基文本代码{{#invoke:}}
的结果。
在解析页面的这一点上,模板都是已经被展开的,解析器函数和扩展标签都已经被处理,而且预存的转换(例如签名的展开以及pipe trick)都已经完成。因此,模块不能在输出文本中使用这些特性。例如,如果一个模块返回"Hello, [[world]]! {{welcome}}"
,页面就会显示“Hello, world! {{welcome}}”。
另一方面,替换引用是在加工的早期阶段处理的,所以只有当其他尝试的替换引用会被处理时才使用{{subst:#invoke:}}
。失败的替换引用因为会保持为维基文本,所以都会在下一次编辑时被处理。这通常需要避免。
模块文档
Scribunto允许模块自动关联wikitext文档页面;默认情况下,模块的“/doc”子页面被用作文档,并且会在模块页面的代码上方显示其内容。例如,"Module:Bananas"的文档将位于"Module:Bananas/doc"。
这也可以使用以下帮助:系统消息 配置:
scribunto-doc-page-name
— 设置用来作文档页面的名称。 模块(除了模块:prefix)的名称会通过$1
。 如果在模块命名空间,这里的页面通常会视为维基文本而不是Lua代码,也不会被{{#invoke:}}
使用。 模块的页面通常是“Module:$1/doc”这样的模块/doc子页面。 请注意,此消息中解析器函数和其他大括号展开可能无法使用。scribunto-doc-page-does-not-exist
— 文档页面不存在时显示的消息。 页面名称传递为$1
。 默认为空。scribunto-doc-page-show
— 文档页面存在时显示的消息。 页面名称传递为$1
。 默认是嵌入包含文档页面。scribunto-doc-page-header
— 查看文档页面本身时显示的标题。 模块的名称(有Module:前缀)传递为$1
。 默认以斜体显示简要说明。
注意模块不可以被直接分类,也不可以直接添加跨维基链接。
这些应该放在文档页面里面的<includeonly>...</includeonly>
标签中,当文档页面被引用到模块页面时,这些分类和跨维基链接就会应用于模块页面。
重命名或移动模块
要重命名或移动模块,使用工具侧边栏中的移动页面链接。你可能想同时移动模块本身,及包含其文档的子页面。
Redirects
MediaWiki版本: | 1.42 Gerrit change 574086 |
Since release 1.42, Scribunto recognizes one particular syntax for redirects (so they’re highlighted on special pages, appear on Special:WhatLinksHere, and so on), and also produces redirects when renaming/moving a module, similarly to how renaming of wikitext pages works (before that, module renames left no redirects behind, now extra rights are needed to suppress the redirect).
要手动创建模块重定向,请使用下列语法:
return require [[Module:Foo]]
将Foo
替换成你想要重定向到的模块名。
Please note that other similarly valid Lua syntax variations (e.g. using quotation marks instead of square brackets, using parentheses around the require
parameter, or even whitespace variations) are still not recognized by MediaWiki as redirects.
Lua语言
变量名称
Lua中的名称(names)(也叫标识符(identifiers))通常可以是任何字母、数字和下划线的字符串,但不可以以数字开头。名称区分大小写;“foo”“Foo”和“FOO”都是不同的名称。
下列关键字是保留的,不能用作名称:
and
break
do
else
elseif
end
false
for
function
if
in
local
nil
not
or
repeat
return
then
true
until
while
以下划线开头后面接大写字母的名称是留给内部的Lua全局变量的。
下面这些文本也属于保留字:
#
%
(
)
*
+
,
-
--
.
..
...
/
:
;
<
<=
=
==
>
>=
[
]
^
{
}
~=
注释
注释在任何地方(除了字符串内)由--
开始。如果--
紧接着开放的中括号,注释就会一直延伸到下一个中括号;否则注释会延伸到这一行的结尾。
-- Lua的注释是由两个连字符(<code>-</code>)开始,延续到一行末尾。
--[[ 多行的字符串和注释
可以被两层中括号括起来。]]
--[=[ 像这样的注释可以紧随其他--[[注释]]。]=]
--[==[ 像这样的注释可以有其他的
--[===[ 修长的 --[=[注释]=] --跟随着
]===] 多次,即使它们所有
--[[ 都没有用匹配的长括号分隔! ]===]
]==]
数据类型
Lua是动态类型语言,意味着变量和函数值都不会有种类,只有值会有。所有的值都有类型。
Lua有8个基本类型,然而只有6个是与Scribunto扩展相关。type()
函数会返回值的类型。
tostring()
能够将值转化为字符串(string)。tonumber()
能够将值转化为数字(number)(如果可能的话),而其他情况则会返回空值(nil)。没有用于将一个值转化为其他的数据类型的明确的函数。
凡是将与字符串(string)连接在一起的地方,数字(number)会自动转化为字符串。使用计算符号时,字符串会由tonumber()
自动转化为数字辨识。当运算中需要将一个值作为布尔值(boolean)时,除了nil和false之外,所有的值都会视为true。
空值(nil)
"nil"
是nil
的数据类型,用来表示这个值不存在。
空值不能用作表(table)中的键(key),且表中某个字段“未指定”与“值为nil”没有区别。
当空值转化为字符串时,其结果会是"nil"
;转化为布尔值(boolean)时,空值会被视为false。
注意:在某些有限的情况下,Lua会区分nil
及无值。
例如,tostring(nil)
返回"nil"
,但tostring()
会抛出错误,因为其第一个参数是必需的。
这种区别与select()函数尤其相关。
布尔值(boolean)
布尔值就是true
(真)和false
(假)。
当布尔值转化为字符串时,结果就是"true"
或者"false"
。
不像很多其他语言,布尔值不会直接转化为数字。而且只有false
和nil作为布尔值时也会视为false;数字0和空字符串都是视为true。
字符串(string)
Lua字符串会视为一系列的8比特字节;这取决于应用程序以哪种特定的编码来解析。
字符串会记录在任何一组单双引号('
或"
)中;就像JavaScript而不像PHP,这两者(指的单引号和双引号)无区别。以下转义序列能被识别:
\a
(响铃,字节7)\b
(退格,字节8)\t
(水平制表符,字节9)\n
(换行,字节10)\v
(纵向制表符,字节11)\f
(换页,字节12)\r
(回车,字节13)\"
(双引号,字节34)\'
(单引号,字节39)\\
(反斜线,字节92)
在字符串代码中直接换行,应该在前面加一个反斜线(\)。字节也可以通过转义序列'\ddd',其中ddd是0~255中的字节值。使用转义序列来代替Unicode字符,则为UTF-8的单个编码字节必须要指定;总的来说,直接输入Unicode字符会更加简单。
字符串也可以用长括号定义。
长括号之间可以夹杂着0个或更多个等号(两边的等号要等量),例如[[
、[=[
或[=====[
。
开放的长括号必须被相应的闭合的长括号(或者说是结束标记)链接,例如]]
、]=]
或者]=====]
.。
特殊情况下,开放的长括号紧跟着连续换行但未被包括的字符串,新一行只会持续到闭合长括号前。
由长括号定义的字符串不会处理转义序列。
-- 此长字符串
foo = [[
bar\tbaz
]]
-- 等效于此引号分隔的字符串
foo = 'bar\\tbaz\n'
注意,在转化为布尔值时,所有的字符串都会视为true(真)。这不像其他的语言将空字符串视为false(假)。
数字(number)
Lua只有一种数字类型,就是典型的64位双精度浮点数。这种格式下,-9007199254740991
(-253 + 1)到9007199254740991
(253 - 1)之间的整数都会准确表达,更大的数和带有小数部分的数将会受到舍入的误差。
常数使用英文句点(.
)来表示小数点,并且不带千位分隔符,例如123456.78
。
数字也可以用不带空格的科学计数法表示,例如1.23e-10
、123.45e20
或1.23E+5
。
整数还可以用0x
前缀开头的十六进制数表示,例如0x3A
。
有几个数值以特殊方式处理:
- 正无穷和负无穷,其求值结果分别大于和小于所有其他数字(NaN除外,见下文)。可以通过两种方式产生:通过
math
库(math.huge
和-math.huge
),或通过数字运算(如1/0
和-1/0
)。 - Lua偶尔会区分
0
和-0
(有关带符号零的更多信息,请参阅-0)。0
和-0
在几乎所有情况下都是严格等价的,但在少数数字运算中表现不同(例如,1/0
返回无穷大,而1/-0
返回负无穷大)。这种区别也会影响从数字到字符串的转换(反之亦然)。 - 正NaN和负NaN(意为Not A Number,即不是数字)。这两个值无对应常量,但
0/0
的值为负NaN。请注意,两种NaN都有一个独特的性质,即任何涉及它们的比较都会得出false
(这意味着它们甚至不等于自己)。两者之间唯一的实际区别在于其与字符串间的类型转换(见下文)。
注意,在转换为布尔值时,任何数字(包括0
, -0
、无穷和NaN)都会被视为true。这不像其他语言,0
通常视为false。数字在转换为字符串时,有穷数会以十进制小数表示,特别当大于或等于1014时使用科学计数法(例如"1e+14"
);无穷转换为"inf"
和"-inf"
;NaN转换为"nan"
和"-nan"
。
已知问题:在编译脚本时,Lua解释器会将所有0
和-0
的实例视为其中最先遇到的一者,这意味着tostring(0)
、1/-0
等等的返回值会受到它们在代码中出现的位置的影响。
这可能会导致意外的结果,特别是如果0
的所有实例都在返回时转换为"-0"
。
如若必要,可以通过使用tonumber("0")
和tonumber("-0")
生成零值来回避这一问题,这似乎不会导致该问题或受到该问题的影响。参见[1]。
表(table)
Lua的表是关联数组(associative arrays),很像PHP的数组和JavaScript的对象(object)。
表要用一对花括号创建。空表是{}
。创建有多个字段的表时,逗号和分号可以分隔表中的各个字段。表的内容可以用以下形式表示:
- *
[expression1] = expression2
表示以expression1为键,以expression2为对应值。 - *
name = expression
等价于["name"] = expression
。 - *
expression
大致等价于[i] = expression
,其中i是从1开始数的整数,随表中每次使用该形式的字段说明而增加。如果这是最后一个字段说明符,且表达式有多个值,所有的值都会使用;否则只有第一个会保留。
表中的字段用中括号访问,例如table[key]
。字符串键(key)同样也可以用作点来表示的名字,例如table.key
就与table['key']
等价。调用表中的一个函数也可以用冒号,例如table:func( ... )
,相当于table['func']( table, ... )
或者table.func( table, ... )
。
数组(也称序列或列表)是从1到N的所有正整数都对应非nil值,且比N大的正整数都对应nil的表。很多Lua函数仅会操作数组,忽略所有的非正整数的键。
不像很多其他的语言(例如PHP或JavaScript),在Lua任何值(除了nil和NaN)都可以作为键,而且不会执行类型转换。参看下面的示例:
-- 创建表
t = {}
t["foo"] = "foo"
t.bar = "bar"
t[1] = "一"
t[2] = "二"
t[3] = "三"
t[12] = "数字十二"
t["12"] = "字符串十二"
t[true] = "true"
t[tonumber] = "是的,即使函数也可以用作表格键"
t[t] = "是的,表格也可以用作表格的键,即使是它本身。"
-- 这将创建一个大致相当于上面的表
t2 = {
foo = "foo",
bar = "bar",
"一",
"二",
[12] = "数字十二",
["12"] = "字符串十二",
"三",
[true] = "true",
[tonumber] = "是的,即使函数也可以用作表格键",
}
t2[t2] = "是的,表格也可以用作表格的键,即使是它本身。"
类似地,任何非nil的值都可以在表中储存为值。将表中存储nil相当于删除表中的对应的键,并且调用表中任何一个不存在的键都会返回nil。
注意,在Lua中,表从来不会复制出一个独立的新表;如果表作为一个参数传递到函数,那么函数能修改表中的键或值,这些变化在调用者(caller)的作用域中都会可见。
当转化为字符串时,结果通常是"table",但使用__tostring
元方法可以重写这个转化方法。作为布尔值时,即使是空的表也会视为真(true)。
函数(function)
Lua中的函数是一等的(first-class)的值:可以匿名创建,或作为参数传递,或给变量赋值,等等。
函数通过function
关键字创建,并使用圆括号调用。有一些语法糖可以用于具名函数、局部函数和表的成员函数。细节见下文的函数声明和函数调用。
Lua函数是闭包,这意味着它们维护对声明它们的作用域的引用,并可以访问和操纵该作用域中的变量。
类似于表,如果函数一个函数被分配给另一个变量,或者作为参数传递给另一个函数,它仍然是相同的被调用的底层“函数对象”。
函数转化为字符串时,结果是"function"。
不支持的类型
用户数据(userdata)用来储存其他语言中的值;例如,一个用户数据可以用来储存C的指针或结构。使用Scribunto运行环境不允许使用用户数据。
线程类型代表协程的句柄,在Scribunto的沙盒中不可用。
上值
单个函数内最多能获取60个不同的上值(upvalue)。上值即一个在函数外定义,而在函数内使用的值。上值包括:
- 变量(有许多元素的表记为1个上值)
- 函数(只计有关函数直接调用的,不计其依赖部分)
只有对以上变量或函数的调用才会计入,从而使其超出限制;未被调用的,即便其存在,也不构成超出限制的条件。重复访问同一上值不会进一步耗尽限制。
元表
每个表都可以关联另一个表,成为元表(metatable)。元表的字段将由特定的操作符或函数使用,从而为表指定不同的或者回落的行为。表的元表通过getmetatable()函数获取,通过setmetatable()函数设置。
访问元函数时,会像rawget()这样访问元表字段。
以下元表字段可以影响表本身:
- __index
- 如果表访问
t[key]
返回nil就使用这个。 如果这个字段的值是表,访问就会在这个表中重复进行,例如__index[键]
(会调用这个表的元表的__index)。 如果这个字段的值是函数,函数就会像__index( t, 键 )
这样调用。 rawget()函数会绕过这个元方法。 - __newindex
- 这个元方法用于将键赋值到表中,即
t[键]=值
,但是rawget( t, key )
会返回空值(nil)。 如果这个字段的值是表,赋值就会转而在这个表中进行,例如__newindex[键] = 值
(会调用这个表的元表的__newindex)。 如果这个字段的值是函数,那么函数就会像这样调用:__newindex( t, 键, 值)
。 rawset()函数会绕过这个元方法。 - __call
- 对表应用函数调用语法
t( ... )
时,就会使用这个元方法。 这个值必须是能以__call( t, ··· )
的形式调用的函数。 - __mode
- 这用于使表保持弱引用(weak references)。 这个值一定是一个字符串。 默认情况下,任何一个值被作为表格中的键或值时是不会被垃圾回收的。 但如果元字段包含字母'k',且没有非弱引用,键可能会被作为垃圾收集。而且如果包含'v'则值有可能也会作为垃圾收集;其他的情况,对应的键和值都会从表中移除。 注意,如果在表用作元表之后字段被改变,则行为未定义。
其他元表字段包括:
注意:在Lua中,所有的字符串都会共用一张元表,其__index
就是指的string
表。在Scribunto中,这个元表和全局引用的string
表都不可访问;对模块可用的string表是一个副本。
变量
变量是储存值的地方。Lua有三种变量:全局(global)变量、局部(local)变量和表(table)中的字段(field,又称“域”)。
名称分为全局和局部变量(或者是函数变量,是局部变量的一种)。定义一个局部变量,可以使用关键词local
,否则默认视为全局变量。任何没有赋值的变量都会视为有nil值。
全局变量储存在叫做环境的Lua表中;这个表通常是作为全局变量_G
的值。这个全局变量表也可以设置元表;__index和__newindex元方法都可以用于全局变量表,就像其他的表一样。
函数的环境可以使用getfenv()函数获取,使用setfenv()函数修改;在Scribunto中,这些函数如果全部可用,就会受到严重限制。
局部变量是有词法作用域的;参见局部变量定义了解详细信息。
表达式
表达式是有值的内容:直接量(数字、字符串、true、false、nil)、匿名函数声明、表构造函数、变量引用、函数调用、变量参数表达式、用括号括起来的表达式、组合有一元运算符的表达式、和与二元运算组合的表达式。
大多数表达式都有一个值;函数调用和变量参数表达式可以有任何数量个值。注意用括号括一个函数调用或变量参数表达式只能保留第一个值,其他的值会失去。
表达式列表是逗号分隔的表达式列表。除了最后一个表达式以外,所有的值都只能是一个值(丢弃附加值,如果表达式没有值则使用nil);最后一个表达式的所有值都包含在表达式列表的值中。
算数运算符
Lua支持以下常见的算数运算符:加减乘除、模运算、幂和取反。
当所有操作值为数字或字符串时,即使用tonumber()返回非nil时,这些操作符有他们通常的意义。
如果一个操作数是一个有合适的元方法的表,元方法就会被调用。
操作 | 功能 | 示例 | 元方法 | 注释 |
---|---|---|---|---|
+ | 加法 | a + b | __add | |
- | 减法 | a - b | __sub | |
* | 乘法 | a * b | __mul | |
/ | 除法 | a / b | __div | 除以零不会出错,会返回NaN或者无穷大 |
% | 模运算 | a % b | __mod | 定义为a % b == a - math.floor( a / b ) * b
|
^ | 幂运算 | a ^ b | __pow | 允许非整数指数 |
- | 取相反数 | -a | __unm |
关系运算符
Lua的关系运算符是==
、~=
、<
、>
、<=
和>=
。关系运算的结果一定是布尔值(boolean)。
等于号(==
)首先比较两个值的种类;如果两个值是不同的种类,结果为假(false)。然后比较值:空值、布尔值、数字和字符串照常比较。对于函数,则是看两个函数是否引用同一个准确的函数对象;像这样检测两个不同的(但作用相同的)匿名函数function() end == function() end
一定会返回假(false)。表也会默认像函数这样比较,但是可能会由于使用__eq元方法而改变结果。
不等号(~=
)与等于号作用相反。
对于排序运算符,如果两者都是数字,或者两者都是字符串,则直接进行比较。其次检查元方法:
a < b
使用__lt
a <= b
使用__le
如果可用,或者__lt
可用,那么它等价于not ( b < a )
a > b
等价于b < a
a >= b
等价于b <= a
如果必需的元方法不可用,会产生错误。
逻辑运算符
逻辑运算是and
(与)、or
(或)和not
(非)。在逻辑运算中,只有空值(nil)和false被视为false,其他的都被视为true。
对于and
,如果左边的操作数被视为假,那么被返回这个操作数,将右边的操作数忽略;否则返回右边的操作数。
对于or
,如果左边的操作数视为真,那么返回左边的操作数,忽略右边的操作数;否则返回右边的操作数。
对于not
,其结果一定是布尔值(true或false)。
注意and
和or
采用短路求值。例如,如果foo()
返回的第一个值为false或nil,foo() or bar()
将只会调用bar()
。
连接运算符
连接运算符就是两个点(dot),比如a .. b
。如果两个操作数都是数字或字符串,它们会被转化为字符串然后返回。但是如果__concat元方法可用,就会使用这样的元方法。如果它存在但无效,则会产生错误。
注意Lua的字符串是不可变的(immutable),而且Lua不提供任何类型的“字符串构造器(string builder)”,所以反复进行a = a .. b
会必须为每次迭代创建一个新字符串,并最终将旧字符串作为垃圾收集。如果许多字符串都需要连接,则应使用string.format(),或将所有的字符串添加到一个序列然后最后使用table.concat()连接。
长度运算符
长度运算符是#
,像#a
这样使用。如果a
是字符串,会返回字符串的字节长度。如果a
是序列表,会返回序列的长度。
如果a
是一个不是序列的表,#a
会返回0或者一个索引值N使得aa[N]
不是nil而aa[N+1]
是nil,即使有的更高的索引不是nil值。例如,
-- 这不是序列,因为aa[3]是nil而aa[4]不是。
a = { 1, 2, nil, 4 }
-- 会输出2或4。
-- 即使这个表没有被修改,这个值也有可能改变。
mw.log( #a )
运算优先级
Lua的運算次序,从高到低为:
^
not
#
-
(负号)*
/
%
+
-
(减号)..
<
>
<=
>=
~=
==
and
or
在同一级中,二元运算符会从左到右运算,例如a / b / c
相当于(a / b) / c
。幂运算和连接会从右往左,例如a ^ b ^ c
相当于a ^ (b ^ c)
。
函数调用
Lua的函数调用与其他的语言很类似:函数名称后面跟着被括号括起来的参数列表。
func( 表达式列表 )
和Lua表达式列表的通常情况一样,列表中的最后一个表达式可以提供多个参数值。
如果传递给函数的参数比函数定义中的参数少,则额外的参数将被赋值nil。如果表达式列表的值比参数多,多余的值会被舍弃。可以让函数接受可变个数的参数,参见函数声明的细节。
Lua允许直接调用由函数返回的值,例如func()()
。如果需要比变量访问更复杂的表达式来确定要调用的函数,则可以使用括号表达式来代替变量访问。
Lua的语法有两个常见的语法糖例子。第一个是当一个表被当做对象使用,并且这个对象有一个函数被调用,那么语法
table:name( 表达式列表 )
完全等同于
table.name( table, 表达式列表 )
第二种常见的情况就是Lua通过含有名称至值的映射的表作为函数唯一参数实施命名参数的工具。这种情况下,包围着参数的括号可以省去。如果将一个(由引号或中括号分割的)字符串作为调用函数时的唯一参数,那么包围着这个参数的括号也可以省去。比如调用
func{ arg1 = exp, arg2 = exp } func"string"
等同于
func( { arg1 = exp, arg2 = exp } ) func( "string" )
它们也可以被组合使用。以下使用是等价的:
table:name{ arg1 = exp, arg2 = exp } table.name( table, { arg1 = exp, arg2 = exp } )
函数声明
函数的定义语法如下:
function nameoptional ( var-listoptional )
语句块
end
var-list中的所有变量对函数都是局部的,这些变量被函数调用的表达式列表赋值。在这个语句块中,多余的局部变量会被忽略。
函数被调用时,block中的语句会在由var-list创建与变量表对应的局部变量和指定值之后执行。如果执行到返回语句,语句块就会退出,函数调用表达式的值就会是返回语句给予的值。如果执行到代码段末尾,还没有返回语句,则函数调用返回的结果是0个值。
Lua函数是词法闭包。一个常见的习惯用法是在函数声明的作用域内声明“私有静态(private static)”变量作为局部变量。比如,
-- 这会返回将它的参数增加一个数字的函数
function makeAdder( n )
return function( x )
-- 外面的这个n在这里是可以加到x中的
return x + n
end
end
local add5 = makeAdder( 5 )
mw.log( add5( 6 ) )
-- 输出11
函数可以声明接受可变数量的(即任何数量个)参数,通过将...
作为变量列表的最后一项:
在这个语句块内,可以使用变量表达式...
,结果会是函数调用中的所有额外的值。比如,
local join = function ( separator, ... )
-- 把额外的变量收集到一个新表中
local args = { ... }
-- 获得当前额外变量的准确个数
local n = select( '#', ... )
return table.concat( args, separator, 1, n )
end
join( ', ', 'foo', 'bar', 'baz' )
-- 返回字符串"foo, bar, baz"
select()函数就是用来作用于这些参数表达式的;特别地,如要获取参数表达式的值的数量,应当使用select( '#', ... )
而非#{ ... }
来数参数表达式有多少个,因为{ ... }
不一定是序列。
Lua为将函数声明和赋值提供到变量中提供语法糖;参见函数声明语句的细节。
注意这个不会起效:
local factorial = function ( n )
if n <= 2 then
return n
else
return n * factorial( n - 1 )
end
end
因为这个函数声明是在局部变量赋值声明完成之前就处理好的,函数主体中的“factorial”会指向函数外(通常是未定义的)变量。这个问题可以通过先声明一个局部变量然后再将它分配到后来的声明中,或者使用函数声明语句语法。
语句
语句是执行的基本单元:一个赋值、控制结构、函数调用、变量声明,等等。
代码块(chunk)是语句(statements)的序列,可以由分号分开。一个代码块基本上被考虑为匿名函数的主体,所以它可以声明局部变量,接受参数,并返回值。
语句块(block)也是语句序列,就像一个代码块(chunk)。语句块可以被分隔以创建单个语句(statement):$1。这些通常用来限制局部变量的作用范围,或者在另一个块的中间加入return
或break
。
赋值
变量列表 = 表达式列表
variable-list是由逗号分隔的变量;expression-list是由逗号分隔的一组一个或多个表达式。所有的表达式都会在赋值之前被求值,所以a, b = b, a
会交换a与b的值。
局部变量定义
local 变量列表
local 变量列表 = 表达式列表
局部变量可以在一个语句块或代码块内任意地方声明。第一种形式,不需要表达式列表,声明变量但不赋值,所以所有变量的值都是nil。第二种形式为局部变量赋值,参见上面的赋值。
注意局部变量从局部变量声明后的语句中才可见。因此local x = x
这样的声明声明了一个名为x的局部变量,并将外层范围中x的值赋予这个变量。局部变量只在其声明的语句块结尾前的地方生效。
控制结构
while 表达式 do 语句块 end
while语句会在表达式结果为true时,反复执行语句块。
repeat 语句块 until 表达式
repeat语句会反复执行语句块,直到表达式结果为true。语句块内声明的局部变量可以用于表达式中。
for 名称 = 表达式1, 表达式2, 表达式3 do 语句块 end
for 名称 = 表达式1, 表达式2 do 语句块 end
for循环的第一种形式会声明一个局部变量,然后从exp1以exp3的步长到exp2重复语句块。注意exp3可以省略,相当于1,但是非数字值比如nil
和false
是错误的。循环开始前,所有的表达式都会先被计算。
这种形式的for循环大致相当于
do
local var, limit, step = tonumber( exp1 ), tonumber( exp2 ), tonumber( exp3 )
if not ( var and limit and step ) then
error()
end
while ( step > 0 and var <= limit ) or ( step <= 0 and var >= limit ) do
local name = var
block
var = var + step
end
end
不过变量var、limit和step在其他地方都不可访问。注意变量“name”是对语句块是局部变量;如果要在循环以外用它的值,它必须被复制到在循环外面定义的变量。
第二种形式的for循环会与迭代函数一起作用。就像在第一种形式里,表达式列表会在开始循环之前就赋值了。
这种形式的for循环大致相当于
do
local func, static, var = expression-list
while true do
local var-list = func( static, var )
var = var1 -- ''var1''是''var-list''中的第一个变量
if var == nil then
break
end
block
end
end
除了变量func、static和var在其他地方不能被获得。注意var-list中的变量在语句块中相当于局部变量;如要在循环外使用它们,需要复制到在循环之外声明的变量。
通常expression-list是返回3个值的一个函数调用。如果迭代器函数可以被写入,那么只取决于传入的参数,这会更加有效。否则,在Lua中编程建议返回闭包比返回表更好,因为静止的变量在每次迭代更新其成员。
if 表达式1 then 语句块1 elseif 表达式2 then 语句块2 else 语句块3 end
当表达式1返回true时执行语句块1,否则,当表达式2返回true时执行语句块2,否则执行语句块3。else block3
部分可以省去,elseif exp2 then block2
部分可以重复,也可以省去。
return 表达式列表
return语句用来从函数或者代码块(只是一个函数)返回值。表达式列表是由逗号分隔开的零个或更多个表达式。
Lua实现尾调用(tail calls)。如果表达式列表包含一个函数调用,对那个函数的调用会重新使用当前的堆栈项(stack frame)。这可用于处理调用堆栈的函数,比如getfenv()
和debug.traceback()
。
返回语句必须是语句块的最后一个语句。如果某些原因语句块的中间需要返回,那么可能需要明显的语句块do return end
。
break
break语句用来中止一个while、repeat或for循环的执行,并跳到循环后面的语句。
break声明必须是语句块(block)的最后一个声明。如果某些原因语句块的中间需要中断,那么可能需要明显的语句块do break end
。
与其他一些编程语言不同,Lua没有用于循环的“continue”语句(即,在不完全中断整个循环的情况下进入下一次迭代的语句)。
不过,通过在主循环内直接嵌套repeat ... until true
语句块即可直接实现相同的效果,该语句块对于主循环的每次迭代仅迭代一次(因为其条件始终为true)。
这样,再使用break
语句就只会中断内层循环,实际效果就是让主循环直接进入下一次迭代。
如果需要在主循环中使用break
语句,只需声明一个每次内层循环完成时都会检查的变量,并在必要时设置它即可。
函数调用作为语句
函数可以作为语句被调用,此时函数只会起到任何的“副作用(side effects)”(例如mw.log()向日志输出信息),返回的值会被忽略。
函数声明语句
Lua提供了语法糖来使得函数的定义更加自然。以下几种定义相互等价。
-- 基本声明 function func( var-list ) 语句块 end func = function ( var-list ) 语句块 end
-- 局部函数 local function func( var-list ) 语句块 end local func; func = function ( var-list ) 语句块 end
-- 作为表中的字段的函数 function table.func( var-list ) 语句块 end table.func = function ( var-list ) 语句块 end
-- 作为表的方法的函数 function table:func( var-list ) 语句块 end table.func = function ( self, var-list ) 语句块 end
注意,这里的冒号符号与函数调用的冒号符号相类似,在参数列表的开头添加了一个隐式参数,名为self
。
错误处理
错误可以通过error()和assert()“抛出”,使用pcall() 或者xpcall()可以“捕获”错误。注意,某些Scribunto的内部错误是不能被Lua层面的代码捕获处理。
垃圾回收
Lua能自动管理内存。这意味着你不需要关心新建对象时内存空间的申请,或者对象不需使用时内存空间的释放。Lua的内存管理会自动执行“垃圾回收”,将不会再被访问的死对象或者被弱引用保持的对象的内存空间收回。几乎所有Lua类型元素都能被回收,包括表、方法、字符串等。
垃圾回收是自动运行的,不能被Scribunto配置。
标准库
Lua标准库为Lua提供基本的性能和关键功能。本文档只给出Lua标准库中在Scribunto启用的一部分内容。
基本函数
_G
这个变量持有对当前全局变量表的引用;全局变量foo
也可以通过_G.foo
访问。注意,然而,对_G本身并没有什么特别的,可能被以同样的方式作为任何其他变量:
foo = 1
mw.log( foo ) -- 输出1
_G.foo = 2
mw.log( foo ) -- 输出2
_G = {} -- _G不再指向全局变量表
_G.foo = 3
mw.log( foo ) -- 还是输出2
全局变量表可以当作普通的表来使用。例如,
-- 调用一个名称存储在变量中的函数
_G[var]()
-- 输出所有全局变量的名称和转化为字符串后的值
for k, v in pairs( _G ) do
mw.log( k, v )
end
-- 输出新全局变量的创建
setmetatable( _G, {
__newindex = function ( t, k, v )
mw.log( "Creation of new global variable '" .. k .. "'" )
rawset( t, k, v )
end
} )
_VERSION
包含正在运行的Lua语言版本的字符串,例如“Lua 5.1”。
assert
assert( v, message, ... )
如果v
是nil或false,抛出错误,message
就会用作错误的文本:如果错误文本为nil(或者未指定),则文本是"assertion failed!"(“断言失败!”);如果是字符串或者数字,文字就是那个值;否则assert本身就会抛出错误。
如果v
是任何其他的值,assert就会返回包括v
和message
在内的全部变量。
在Lua的一个比较常见的惯用用法是,一个函数在正常操作时返回true值,并在失败时返回nil或false作为为第一个值、错误信息作为第二值。容易的错误检查可以通过调用函数assert
来实现:
-- 这个不会检查错误
local result1, result2, etc = func( ... )
-- 这个作用相同,但是会查错
local result1, result2, etc = assert( func( ... ) )
error
error( message, level )
用文本message
来发出一个错误。
error
一般会提供出错的位置的信息。如果level
是1或者省略,那么信息就是调用error
本身的位置,2使用被调用错误的函数调用的位置,等等。0会省略位置信息。
getfenv
getfenv( f )
注意,这个函数可能会无效,取决于配置中的allowEnvFuncs
。
返回运行环境(全局变量表),就像f
指定的:
- 如果1、nil或者未指定,返回调用
getfenv
函数的环境。通常这与_G相同。 - 整数2~10返回更高一级的环境。例如,2返回被这一个函数调用的函数的环境,3返回调用这一个函数的函数的环境,以此类推。如果这个堆栈值越高,错误也会随之上升,否则这个堆栈级别会返回尾调用(tail call)。
- 传递函数返回在调用该函数时将使用的环境。
通过所有的基本函数和Scribunto基本库函数使用的环境都被保护。尝试访问这些环境中使用getfenv
将返回nil。
getmetatable
getmetatable( table )
如果元表拥有__metatable
字段,这个值就会直接返回,而不是返回事实上的元表。
ipairs
ipairs( t )
返回3个值:迭代函数、表t
和0。它是供for
的迭代形式使用的:
for i, v in ipairs( t ) do
-- process each index-value pair
end
它会迭代数对(1, t[1])、(2,t[2])等,直到t[i]是nil时。
如果__ipairs
元方法存在,那么标准行为会被覆盖,调用会返回与__ipairs( t )
的返回值一致的值。
next
next( table, key )
允许遍历表中的键。如果key
是nil或者未指定,返回表中的第一个键和值,否则,返回下一个键和值。如果没有更多的键可以用,返回nil。可以通过使用next( t ) == nil
来检查表是否是空的。
注意键被返回的顺序是没有指定的,即使表有数字的索引(indexes)。如要以数字顺序遍历表,使用数字的for或ipairs。
如果遍历时使用next,任何不存在的键被赋给一个值,则行为未定义。可以给一个存在的字段赋一个新的值(包括nil)。
pairs
pairs( t )
返回三个值:迭代器函数(next或者类似的)、表t
和nil。这是用于for
的迭代器形式。
for k, v in pairs( t ) do
-- 处理每个键值对
end
这会遍历t
中的键值对,就像next做的那样。参考next的文档以了解遍历期间修改表的限制。
如果__pairs元方法存在,那么标准行为会被覆盖,调用会返回与__pairs( t )
的返回值一致的值。
pcall
pcall( f, ... )
用指定的参数在“保护模式”下调用函数f
。这意味着如果在调用f
时出错,pcall会返回false与错误消息。如果没有错误发生,pcall会返回true与调用返回的所有值。
用伪代码表示,pcall
的定义类似如下:
function pcall( f, ... )
try
return true, f( ... )
catch ( message )
return false, message
end
end
rawequal
rawequal( a, b )
与a == b
相同,只是忽略了所有__eq元方法。
rawget
rawget( table, k )
与table[k]
相同,只是忽略了所有__index元方法。
rawset
rawset( table, k, v )
与table[k] = v
相同,只是忽略了所有__newindex元方法。
select
select( index, ... )
如果index
是数字,返回...
中从那个索引往后的所有参数。
如果index
是字符串"#"
,返回...
中的参数个数。
注意:与表不同,参数列表(包括变参表达式...
)将nil
视作一个确切的值(对于表中有nil
时的问题,参见#和unpack的文档)。例如:
select(2, "foo", "bar")
返回"bar"
。select(2, "foo", nil, "bar", nil)
返回nil, "bar", nil
。select("#", "foo", "bar")
返回2
。select("#", "foo", "bar", nil)
返回3
。
也就是说,select
有点像以下代码(只不过它还处理最后一个非nil参数以后的nil
参数):
function select( index, ... )
local t = { ... }
local maxindex = table.maxn( t )
if index == "#" then
return maxindex
else
return unpack( t, index, maxindex )
end
end
setmetatable
setmetatable( table, metatable )
设置表的元表,metatable
可能是nil,但是必须是清楚地提供的。
如果当前的元表有一个__metatable字段,setmetatable
会报错。
tonumber
tonumber( value, base )
尝试将value
转化为数字。如果已经是数字或者可以转化为数字的字符串,tonumber
就会返回这个数字,否则会返回nil。
base
是可选的,默认为10,指定解析数字的进位基数。这个基数可以是2到36之间的任何整数。对于大于10,字母A(大小写均可)代表10,B代表11,以此类推,Z代表35。
十进制下,值可以有小数部分,或者以科学计数法表示,而且甚至可以以“0x”开头以表示16进制。其他情况,只会接受不带符号的整数。
tostring
tostring( value )
将value
转化为字符串。参考上方的数据类型以了解各种类型被转换时的细节。
对于表,标准的转换行为可以被__tostring元方法覆盖。如果这个元方法存在,那么调用tostring会返回由__tostring( value )
返回的单个值。
type
type( value )
以字符串形式返回value
的类型"nil"
、"number"
、"string"
、"boolean"
、"table"
或"function"
。
unpack
unpack( table, i, j )
从给定的表返回值,像table[i], table[i+1], ···, table[j]
这样的如果被写出会直接返回。i
和j
如果没有给出或者是nil,取其默认值1和#table
。
如果表中没有特定键的值,unpack将为其返回nil。例如,unpack({"foo", [3] = "bar"}, 1, 4)
返回"foo", nil, "bar", nil
。
注意如果table
不是一个序列且j
是nil或未指定,则结果是不确定的,参考长度操作符以了解详细。
xpcall
xpcall( f, errhandler )
这个很像pcall
,只是错误消息在返回之前传递到函数errhandler
中。
用伪代码表示,xpcall
的定义类似如下:
function xpcall( f, errhandler )
try
return true, f()
catch ( message )
message = errhandler( message )
return false, message
end
end
调试库
debug.traceback
debug.traceback( message, level )
以字符串的形式返回调用栈。可选的message参数会被连接到调用栈信息的前面。可选的level参数表示返回多少层调用栈。
数学(math)库
math.abs
math.abs( x )
返回x
的绝对值。
math.acos
math.acos( x )
返回x
的反余弦值(以弧度表示)。
math.asin
math.asin( x )
返回x
的反正弦值(以弧度表示)。
math.atan
math.atan( x )
返回x
的反正切值(以弧度表示)。
math.atan2
math.atan2( y, x )
使用两个参数的符号(signs)以找到结果的象限,返回y/x
的反正切值(弧度制)。
math.ceil
math.ceil( x )
返回不小于x
的最小整数。
math.cos
math.cos( x )
返回x
(以弧度表示)的余弦值。
math.cosh
math.cosh( x )
返回x
的双曲余弦值。
math.deg
math.deg( x )
将弧度角x
转化为角度。
math.exp
math.exp( x )
返回。
math.floor
math.floor( x )
返回小于或等于x
的最大整数。
math.fmod
math.fmod( x, y )
返回x
除以y
的余数,并将商舍入到零。比如,math.fmod( 10, 3 )
产生1
。
math.frexp
math.frexp( x )
返回像这样的两个值m
和e
:
- 如果
x
有限且非零,那么、e
是整数,m
的绝对值在区间内 - 如果
x
是零,那么m
和e
都是0 - 如果
x
是NaN(非数字)或无穷大,那么m
是x
而e
不指定
math.huge
代表正无穷大的值;比任何其他数值都要大或与之相等。
math.ldexp
math.ldexp( m, e )
返回(e
是整数)。
math.log
math.log( x )
返回x
的自然对数。
math.log10
math.log10( x )
返回x
的以10为底的对数。
math.max
math.max( x, ... )
返回其参数的最大值。
对于NaN的行为未指定。当前,如果x
是NaN,那么会返回NaN,但是其他的NaN就会被忽略。
math.min
math.min( x, ... )
返回其参数的最小值。
对于NaN的行为未指定。当前,如果x
是NaN,那么会返回NaN,但是其他的NaN就会被忽略。
math.modf
math.modf( x )
返回两个数字,x
的整数部分和x
的小数部分。比如,math.modf( 1.25 )
产生1, 0.25
。
math.pi
的值。
math.pow
math.pow( x, y )
与x^y
相同。
math.rad
math.rad( x )
将角度x
转化为弧度角。
math.random
math.random( m, n )
返回伪随机数。
参数m
、n
可省略,但是如果指定了,则必须能够转化为整数。
- 没有参数时返回区间内的实数。
- 有一个参数时返回区间内的整数。
- 有两个参数时返回区间内的整数。
注意,如果m
或者n
小于−2147483648或者大于2147483647,或者n - m
大于2147483646,那么输出可能会不正确。
math.randomseed
math.randomseed( x )
以x
作为伪随机数生成器的种子。
注意使用同一个种子会导致math.random
输出相同的数列。
math.randomseed( tonumber( mw.getContentLanguage():formatDate( "U" ) ) * 10000 + os.clock() * 10000 )
math.sin
math.sin( x )
返回 x
(以弧度表示)的正弦值。
math.sinh
math.sinh( x )
返回x
的双曲正弦值。
math.sqrt
math.sqrt( x )
返回x
的平方根。与x^0.5
相同。
math.tan
math.tan( x )
返回x
(以弧度表示)的正切值。
math.tanh
math.tanh( x )
返回x
的双曲正切值。
操作系统库
os.clock
os.clock()
返回程序大约使用的CPU时间,以秒为单位。
os.date
os.date( format, time )
- 语言库的formatDate可以被用于更加全面的日期格式。
返回包含日期和时间的字符串或表,以format
为格式。如果格式被省略或者是nil,则使用"%c"。
如果给定了time
,则就是被格式化的时间(参考os.time()
。否则使用当前的时间。
如果format
以'!'开头,则日期按照UTC格式而不是服务器的本地时间。在这个可选字符之后,如果格式是字符串"*t",那么日期返回带有以下字段的表。
- year(完整的)
- month(1~12)
- day(1~31)
- hour(0~23)
- min(0~59)
- sec(0~60,允许闰秒的情况)
- wday(weekday,Sunday是1)
- yday(一年的某一天)
- isdst(夏令时,布尔值,信息不可用时可能不存在)
如果格式不是"*t",那么日期以字符串形式返回日期,按照和C函数strftime相同的规则格式化。
os.difftime
os.difftime( t2, t1 )
返回从t1
到t2
两个时间的秒数。
os.time
os.time( table )
返回代表当前时间的数字。
调用且没有变量时,返回当前时间。若传入了表,则表中编码的时间就会被解析。表必须有years、month、days这几个字段,并且可能也包括hour(默认为12)、min(默认为0)、sec(默认为0)和"isdst"。
包库
require
require( modulename )
加载指定的模块。
首先会检查package.loaded[modulename]
以检查模块是否已被加载,如果是,返回package.loaded[modulename]
。
否则,返回package.loaders
序列中的每一个加载器以尝试寻找模块的加载器。若找到加载器,则调用这个加载器。加载器返回的值存储在package.loaded[modulename]
中并将其返回。
参见package.loaders
以了解可用的加载器的信息。
例如,如果你有一个模块“Module:Giving”其中有如下代码:
local p = {}
p.someDataValue = '您好!'
return p
你可以用以下代码在其它模块载入此模块:
local giving = require( "Module:Giving" )
local value = giving.someDataValue -- 值现在等于 '您好!'
package.loaded
这个表存储已加载的模块。键为模块名称,值为模块被加载时返回的值。
package.loaders
表存储了在加载模块时要用的搜索器函数(searcher function)的序列。每一个搜索器函数会被带有单个参数调用:要加载的模块名称。如果找到模块,搜索器必须返回会事实上加载这个模块的函数,并返回要被require返回的值。否则,返回nil。
Scribunto提供了两种搜索器:
- 在
package.preload[modulename]
中寻找加载器函数 - 在Scribunto提供的模块中寻找模块名称,如果没找到,在“模块:”命名空间下寻找。“模块:”前缀必须提供。
注意没有包括标准的Lua加载器。
package.preload
这个表存储加载器函数,被Scribunto在package.loaders中包括的第一个搜索器。
package.seeall
package.seeall( table )
将table
的__index $3设置为_G。
字符串库
在所有字符串函数中,第一个字符是第1位,而不是像C、PHP、JavaScript中的那样第0位。索引(indexes)可以是负的,表示从字符串最末开始倒数,比如-1表示最后一个字符,-2表示倒数第二个,等等。
警告:字符串库假定单字节字符串编码。不能处理Unicode字符。要对Unicode字符进行操作,使用Scribunto Ustring库中对应的方法。
string.byte
string.byte( s, i, j )
如果字符串被考虑为字节的数组,返回s[i]
、s[i+1]
、···、s[j]
的字节值。i
的默认值为1;j
的默认值为i
。等价于mw.ustring.byte()。
string.char
string.char( ... )
接受零个或更多个整数。返回和长度与参数个数相同的字符串,每个字符的字节值等于其对应的参数。
local value = string.char( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21 ) --值现在是'Hello!'
参看mw.ustring.char()以了解使用Unicode码位而非字节值的类似函数。
string.find
string.find( s, pattern, init, plain )
寻找字符串s
中pattern
的第一个匹配(match)。如果找到一个匹配,find
将返回s
中起止点的序列,否则返回nil。如果匹配模式有捕获物(capture),则在成功的匹配中被捕获的值也会被返回在两个索引之后。
第三个参数init
是可选的,指定从哪里开始搜索,默认值是1,可以是负数。第四个参数plain
也是可选的,如果是true,则会关闭模式匹配机制,则函数做的只是简单地“找子串”操作,pattern
中的字符就不会被看作魔法字符。
注意给了plain
就必须给init
。
参考init
以了解用于Ustring pattern的类似函数,而且init
是按照字符而非字节。
string.format
string.format( formatstring, ... )
返回变量数字的参数将第一个参数(必须是字符串)格式化后的版本。
格式字符串使用printf
格式指定器但有所限制。
'-', '+', ' ', '#',
和'0'
是被认可的。- 支持最多99个整数字段。
'*'
不支持。 - 支持最多99个整数精确度。
'*'
不支持。 - 长度修改器不支持。
- 认可
'c', 'd', 'i', 'o', 'u', 'x', 'X', 'e', 'E', 'f', 'g', 'G', 's', '%',
这些转换器,以及非标准的'q'
。 - 不支持像“%2$s”这样的位置指定器。
转换指定器q
类似于 s
,但是会以特定的专用于表述字符串的格式来形成字符串;字符串会被写在双引号中,所有的双引号、新行、嵌入的零、反斜杠都会被转义。
数字和字符串之间的转换会像数据类型中的描述那样进行,其他类型不会自动转化为字符串。包含NUL字符的字符串(字节值0)不能被正常处理。
string.gmatch
string.gmatch( s, pattern )
返回一个迭代器函数,每次被调用,都会从字符串s
中的pattern
返回下一个捕获。如果pattern
不会指定捕获,则整个匹配都会在每次调用时产生。
对于这个函数,开始的“^
”不是魔法字符,因为这个会避免迭代。它被看做是普通字符。
参看mw.ustring.gmatch()以了解其类似函数,其匹配模式是被扩展的,参考Ustring匹配模式。
string.gsub
string.gsub( s, pattern, repl, n )
将字符串s
的所有(如果给定了n
则前n
个)出现的pattern
替换为由repl
(replacement)指定的替换物,这个替换物可以是字符串、表或者函数。gsub
也会返回第二个值,是匹配到的总次数。
如果repl
是一个字符串,则其值直接用于替换。字符%
用作转义符(escape character):若d是1到9之间的整数,则repl
中任何%d
形式的序列代表第d个被捕获的子串。序列%0
代表整个匹配,序列%%
代表单个%
。
如果repl
是表,则每次匹配查询这个表,其键(key)为第一个捕获物(capture);如果pattern
(匹配模式)中不指定捕获物,则整个匹配用作键。
如果repl
是函数,则每次匹配发生时调用这个函数,所有被捕获的子串都会依次被传入作为参数。如果匹配模式不指定捕获,则整个匹配会作为单个参数传入函数。
如果表格查询或者函数调用返回的值是字符串或者数字,则用作替换字符串,否则,如果是false或nil,则不会进行替换,也就是说原始匹配仍保留在字符串中。
参看mw.ustring.gsub()以了解其类似函数,其匹配模式是被扩展的,参考Ustring匹配模式。
string.len
string.len( s )
返回字符串的字节长度。不会被ASCII NUL字符混淆。等同于#s
。
参看mw.ustring.len()以了解使用Unicode码位而非字节值的类似函数。
string.lower
string.lower( s )
将字符串的所有ASCII大写字符转为小写后返回。所有其他字符不改变。
参考mw.ustring.lower()以了解类似的函数,该函数可以将Unicode定义的所有的大写字母转化为小写字母。
string.match
string.match( s, pattern, init )
寻找字符串中pattern
的第一个匹配,如果找到一个,则match
返回匹配模式中的捕获物,否则返回nil。如果pattern
不指定捕获物,则返回整个字符串。
第三个参数init
是可选的,用来表示从哪里开始搜索,其默认值为1,可以是负数。
参看mw.ustring.match()以了解其类似函数,其匹配模式是被扩展的,参考Ustring匹配模式,而且其默认偏移(init
)是按字符的,而非按字节的。
string.rep
string.rep( s, n )
返回字符串s
重复n
次并连接后的字符串。等价于mw.ustring.rep()。
string.reverse
string.reverse( s )
返回字符串s
被逆转后的字符串(按字节逆转)。
string.sub
string.sub( s, i, j )
返回s
的从i
开始持续到j
的子串(substring);i
和j
可以是负的。如果j
是nil或未指定,则会一直到字符串末尾。
特别地,调用string.sub(s,1,j)
会返回字符串s
的长度j
的前缀,而string.sub(s, -i)
会返回字符串s
的长度为i
的后缀。
参看mw.ustring.sub()以了解使用字符而非字节值的类似函数。
string.ulower
string.ulower( s )
string.upper
string.upper( s )
将字符串的所有ASCII小写字符转为大写后返回。所有其他字符不改变。
参考mw.ustring.upper()以了解类似的函数,该函数可以将Unicode定义的所有的小写字母转化为大写字母。
string.uupper
string.uupper( s )
匹配模式(patterns)
注意Lua的匹配模式类似于正则表达式(regular expression),但是并不一样。特别地,注意正则表达式和PCRE之间的以下区别:
- 用于引用的字符串是百分号(
%
)而非反斜杠(\
)。 - 点(
.
)总是匹配所有字符,包括新行。 - 没有大小写不敏感模式。
- 没有选择功能(
|
操作符)。 - 量词(quantifier,
*
,+
,?
和-
)只能用于单独的字符或者字符类,不能用于捕获组。 - 唯一非贪婪的量词是
-
,相当于PCRE的*?
量词。 - 没有广义的有限量词,比如PCRE中的
{n,m}
。 - 零宽的断言(assertion)有
^
、$
和%f[set]
“边界”模式,像PCRE中的\b
和(?=···)
断言不可用。 - 匹配模式本身不识别像
\ddd
这样的字符转义。然而,由于匹配模式是字符串,这类转义可以用于创建样式匹配字符串的字符串文字中。
注意匹配模式不能包含嵌入的零字节(ASCII NUL,"\0"
)。应该使用%z
。
参考Ustring匹配模式以了解使用Unicode字符的类似的样式匹配机制。
字符类
字符类是一组字符的集合。以下集合可以用于定义字符类。
x
|
(x 不是魔法字符^$()%.[]*+-? 之一)代表字符x 自身。
|
---|---|
.
|
(一个点)代表所有字符。 |
%a
|
代表所有ASCII字母。 |
%c
|
代表所有ASCII控制字符。 |
%d
|
代表所有数字。 |
%l
|
代表所有ASCII小写字母。 |
%p
|
代表所有标点字符。 |
%s
|
代表所有ASCII空白字符。 |
%u
|
代表所有ASCII大写字母。 |
%w
|
代表所有ASCII字母和数字字符。注意这不包含下划线字符(_ ),不同于正则表达式中通常的\w 类。
|
%x
|
代表所有十六进制数字。 |
%z
|
代表所有ASCII NUL,即零字节。 |
%A
|
所有不在%a 中的字符。
|
%C
|
所有不在%c 中的字符。
|
%D
|
所有不在%d 中的字符、
|
%L
|
所有不在%l 中的字符。
|
%P
|
所有不在%p 中的字符。
|
%S
|
所有不在%s 中的字符。
|
%U
|
所有不在%u 中的字符。
|
%W
|
所有不在%w 中的字符。
|
%X
|
所有不在%x 中的字符。
|
%Z
|
所有不在%z 中的字符。
|
%y
|
(y 不是字母或数字字符)代表字符y 。这是转义魔法字符的标准方式。任何标点字符(甚至是非魔法字符)都可以跟'% '用以代表样式匹配中的自身。
|
[set]
|
代表集合set中所有字符的组合。一系列字符可以通过用' 范围和类之间的交互是没被定义的,因此像 |
[^set]
|
代表set的补集。 |
模式条目(pattern item)
模式条目可以是
- 单个字符类,匹配类中的单个字符。
- '
*
'前的单个字符类,匹配这个类中重复0次或者更多次的字符。这个重复项总是匹配可能的最长序列。 - '
+
'前的单个字符类,匹配这个类中重复一次或者更多次的字符。这个重复项总是匹配可能的最长序列。 - '
-
'前的单个字符类,匹配这个类中重复0次或者更多次的字符。不像'*
',这个重复项总是匹配可能的最短序列。 - '
?
'前的单个字符类,匹配这个类中0次或1次出现的字符。 %n
,n可以是1到9之间,匹配相当于第n个被捕获的子字符串(见下)。%bxy
,x和y是两个不同的字符,匹配从x开始、以y结尾的字符,且x和y的数目相等。也就是说,如果从前向后读字符串,读到x时加一,读到y时减一,那么结尾的y是第一次计数到达0时的y。例如,%b()
会匹配两边圆括号成对的字符串。%f[set]
,边界模式,这样的模式条目匹配任何位置的空字符串,且此字符串的下一个字符属于集合set,且前一个字符不属于集合set。集合set在前面已有描述。目标字符串的开始和结尾位置按照字符'\0'处理。
注意,边界模式存在于Lua 5.1,但是该版本的文档没有提及,Lua 5.2中才正式加入,不过Lua 5.2.1中的实现和5.1.0中的是一样的。
模式(pattern)
模式(pattern)是模式条目(pattern item)的序列。
模式开头的^
会匹配字符串的开始处。 模式末尾的$
会匹配字符串的最末尾。其他位置的^
和$
无特殊含义,代表自身。
捕获
模式可以包括用小括号括起来的子模式(sub-patterns),描述了“捕获”。匹配成功时,字符串的匹配捕获的子字符串会被存储(被“捕获”)以备使用。捕获是根据左边的括号被标号的。比如,在模式(a*(.)%w(%s*))
中,匹配a*(.)%w(%s*)
的字符串部分被存储在第一个捕获(所以是第一项),匹配.
的字符被捕获,记为第2项,匹配%s*
的则是第3项。
捕获可以在模式字符串中引用自身,并返回匹配中更早捕获到的文本。比如,([a-z])%1
会匹配任何一对相同的小写字母,而([a-z])([a-z])([a-z])[a-z]%3%2%1
会匹配任何7个字母的回文。
作为特殊情况,空的捕获()
会捕获当前的字符串位置(一个数字)。比如我们对字符串"flaaap"
执行模式"()aa()"
,那么会有两个捕获:3和5。
已知限制:不像Ustring库的模式,String库的模式可能无法包含超过32个捕获,如果超出数量限制,那么String函数可能会抛出错误。因为Ustring库自己有最多10000个字节用于模式(不像String库),因此使用模式不会超过这两个限制,且与两个库都兼容。
表(table)库
这个库的大多数函数假设作为参数的表是序列。
函数table.foreach()
、table.foreachi()
和table.getn()
可能可用但已弃用。应该使用pairs()
的for循环、ipairs()
的for循环和长度操作符。函数pairs()
完全过时,使用了会抛出错误。
table.concat
table.concat( table, sep, i, j )
给定一个所有元素都是字符串或数字的数组,返回table[i] .. sep .. table[i+1] ··· sep .. table[j]
。
sep
的默认值为空字符串,i
的默认值为1,j
的默认值为表的长度。如果i
大于j
,返回空字符串。
table.insert
table.insert( table, value )
table.insert( table, pos, value )
在表table
的位置pos
处插入元素value
,会将其他元素的位置增加1以给这个元素提供插入空间。pos
的默认值为表的长度加1,所以调用table.insert(t, x)
会在表t
的末尾插入x
。
被移动元素的下标至多为#table
。关于当表不是序列时的注意事项,请见长度操作符。
注意:使用pos
参数时,value
不能为nil
。试图向表的中间插入显式的nil
值会导致未定义行为,可能会无法预测地删除表中的元素。
table.maxn
table.maxn( table )
返回给定的表的最大正数索引,或者表没有正数索引时返回零。
会遍历整个表,大致相当于
function table.maxn( table )
local maxn, k = 0, nil
repeat
k = next( table, k )
if type( k ) == 'number' and k > maxn then
maxn = k
end
until not k
return maxn
end
table.remove
table.remove( table, pos )
从表格table
中移走位于pos
处的元素,将后面的元素前移。pos
的默认值为表的长度,所以调用table.remove( t )
会移除表t
的最后一个元素。
被移动元素的下标至多为#table
。关于当表不是序列时的注意事项,请见长度操作符。
table.sort
table.sort( table, comp )
从table[1]
到table[#table]
,按照给定次序就地排序表的元素。
如果给定了comp
,则其必须是接收两个表元素的函数,并且当第一个小于第二个时返回true
(所以not comp(a[i+1],a[i])
会在排序后为true)。
如果没有给定comp
,则使用标准的Lua操作符<
。
排序算法并不稳定;也就是说,当两个元素按照给定的顺序被看作相等时,它们在排序后的相对位置可能会改变。
Scribunto库
所有Scribunto库位于表mw
中。
基本函数
mw.addWarning
mw.addWarning( text )
在预览编辑时加一个警告信息。text
解析为维基文本。
mw.allToString
mw.allToString( ... )
对所有的参数调用tostring(),然后用制表符作为分隔符连接起来。
mw.clone
mw.clone( value )
深拷贝一个值。所有的表和它们的元表被重构,但是新表和旧表共用函数。
mw.getCurrentFrame
mw.getCurrentFrame()
返回目前的框架对象,通常是最近的#invoke
中的框架对象。
mw.incrementExpensiveFunctionCount
mw.incrementExpensiveFunctionCount()
使得“高开销解析器函数”计数器加一,并在其超过限制时抛出异常(参见$wgExpensiveParserFunctionLimit
)。
mw.isSubsting
mw.isSubsting()
如果当前的#invoke
被替换引用时返回true,否则返回false
。参见上方讨论的返回文本。
mw.loadData
mw.loadData( module )
有时一个模块需要大量表格的数据,例如,用于转换计量单位的通用模块可能需要一张大表的已识别的单位及其转换系数。而且有时这些模块会在一个页面中使用多次。每次{{#invoke:}}
都解析大表格的数据会用大量时间。mw.loadData()
正是为了避免这个问题。
mw.loadData
类似于require()
,但是有以下区别:
- 加载的模块每页只会解析一次,而不是每次调用
{{#invoke:}}
就解析一次。 - 加载的模块不会记录在
package.loaded
中。 - 所加载模块返回的值必须是表。不支持其他数据类型。
- 返回的表及其所有子表只能包含布尔值、数字、字符串和其他表。不允许其他数据类型,尤其是函数。
- 返回的表及其所有子表不能有元表。
- 所有的表键必须是布尔值、数字、或字符串。
- 由
mw.loadData()
返回的表有元方法,这些元方法可以为模块返回的表提供只读访问。因为其并不直接包含数据,pairs()
和ipairs()
会起作用,但是其他方法,包括#value
,next()
和表库的函数无法正常运作。
上述假定的单位转换模块可以将其代码存储在“Module:Convert”然后将其数据存储在“Module:Convert/data”,且“Module:Convert”会使用local data = mw.loadData( 'Module:Convert/data' )
来有效地加载数据。
mw.loadJsonData
mw.loadJsonData( page )
这个和上面的mw.loadData()
一样,但是会从JSON页面而非Lua表中加载数据。
JSON内容必须是数组或者对象。
参见mw.text.jsonDecode()
。
mw.dumpObject
mw.dumpObject( object )
将object
序列化为人类可读形式,返回字符串结果。
mw.log
mw.log( ... )
将参数传递到mw.allToString(),然后将结果字符串加载控制台后。
在调试控制台,print()
等价于这个函数。
mw.logObject
mw.logObject( object )
mw.logObject( object, prefix )
调用mw.dumpObject()然后将结果加到控制台输出的后面。如果给定了prefix
,其会被加到控制台输出,紧随一个等于号,位于序列化字符串之前,即输出的字符串会是“prefix = object字符串”。
框架对象(Frame object)
框架对象是接口,可用来访问传递至{{#invoke:}}
和解析器的参数。
注意没有框架库,也没有叫做frame
的全局变量。框架对象通常为被{{#invoke:}}
调用的函数的参数,当然也可以从mw.getCurrentFrame()
获得。
frame.args
用来访问传递到frame的参数的表。例如,一个模块从如下的维基文本调用
{{#invoke:module|function|arg1|arg2|name=arg3}}
那么frame.args[1]
会返回"arg1"
,frame.args[2]
会返回"arg2"
,frame.args['name']
或frame.args.name
会返回"arg3"
。在参数列表迭代可以使用pairs( frame.args )
或ipairs( frame.args )
。
然而,由于Lua实现表迭代器的方式,迭代参数的返回顺序不确定,参数出现在维基文本中的顺序也无从得知。
注意这个表中的值总是为字符串,tonumber()
可以用于在需要时转化为数字。但是,键是数字,即使在调用时清楚提供{{#invoke:module|function|1|2=2}}
,也只会给出被数字键1
和2
索引的字符串值"1"
和"2"
。
就像在MediaWiki模板调用中那样,命名参数(named arguments)会在传递到Lua前移除名称和值的多余空格,而匿名参数(unnamed arguments)不会移除空格。
考虑到性能,frame.args
使用元表,而非直接包含参数。参数值会从根据需求从MediaWiki请求得到。这意味着大多数其他表格方法不会正常生效,包括#frame.args
, next( frame.args )
和表库中的函数。
如果在#invoke的参数中包含了像模板调用和三层括号变量这样的预处理器(preprocessor)语法,那么这些在传递到Lua之后不会被展开,直到值被Lua请求时才会展开。如果在#invoke
的参数中包含了用XML标记形式写的特殊标签,例如<pre>
、<nowiki>
、<gallery>
和<ref>
,这些标签会被转化为strip markers——一种特殊字符串,由删除符(ASCII 127)开始,在从#invoke
返回后转化为HTML。
frame:callParserFunction
frame:callParserFunction( name, args )
frame:callParserFunction( name, ... )
frame:callParserFunction{ name = string, args = table }
- 注意使用了命名参数。
调用解析器函数,返回适当的字符串。这相比于frame:preprocess
更优,但如果有可能,最好优先使用原生的Lua函数或Scribunto库函数。
以下调用与註出的维基文本基本相同:
-- {{ns:0}}
frame:callParserFunction( 'ns', { 0 } )
frame:callParserFunction( 'ns', 0 )
frame:callParserFunction{ name = 'ns', args = { 0 } }
-- {{#tag:nowiki|some text}}
frame:callParserFunction( '#tag', { 'nowiki', 'some text' } )
frame:callParserFunction( '#tag', 'nowiki', 'some text' )
frame:callParserFunction( '#tag:nowiki', 'some text' )
frame:callParserFunction{ name = '#tag', args = { 'nowiki', 'some text' } }
-- {{#tag:ref|some text|name=foo|group=bar}}
frame:callParserFunction( '#tag', { 'ref',
'some text', name = 'foo', group = 'bar'
} )
注意,函数名称和参数不会在传递到解析器函数之前被预处理(preprocess),frame:expandTemplate()也是如此。
frame:expandTemplate
frame:expandTemplate{ title = title, args = table }
- 注意使用了命名参数。
这等同于调用frame:callParserFunction(),函数名称为'msg'
(参阅Help:魔术字#嵌入修饰器),并在args
前加上title
。
这是嵌入。函数调用:
frame:expandTemplate{ title = 'template', args = { 'arg1', 'arg2', name = 'arg3' } }
在Lua脚本中的行为大致和{{template|arg1|arg2|name=arg3}}
在维基文本中的行为一样。在嵌入中,如果页面名没有命名空间前缀,那么函数会认为页面在模板命名空间内。
注意标题与参数在传递到模版之前并未预处理:
-- 这与维基文本{{template|{{!}}}}基本相同
frame:expandTemplate{ title = 'template', args = { '|' } }
frame:callParserFunction{ 'msg', { 'template', '|' } }
-- 这与维基文本{{template|{{((}}!{{))}}}}基本相同
frame:expandTemplate{ title = 'template', args = { '{{!}}' } }
frame:callParserFunction{ 'msg', { 'template', '{{!}}' } }
frame:extensionTag
frame:extensionTag( name, content, args )
frame:extensionTag{ name = string, content = string, args = table_or_string }
这相当于调用frame:callParserFunction(),其函数名称为'#tag'
(參見Help:魔术字#杂项),并在args
前添加了name
和content
。
-- 这些都相同
frame:extensionTag( 'ref', 'some text', { name = 'foo', group = 'bar' } )
frame:extensionTag{ name = 'ref', content = 'some text', args = { name = 'foo', group = 'bar' } }
frame:callParserFunction( '#tag', { 'ref' ,
'some text', name = 'foo', group = 'bar'
} )
-- 这些都相同
frame:extensionTag{ name = 'ref', content = 'some text', args = { 'some other text' } }
frame:callParserFunction( '#tag', { 'ref',
'some text', 'some other text'
} )
frame:getParent
frame:getParent()
若在由{{#invoke:}}
创建的框架调用,返回调用了{{#invoke:}}
的页面的框架。若在该框架调用,会返回nil。
比如,如果模板{{Example}}
包含代码{{#invoke:ModuleName|FunctionName|A|B}}
,而另一页通过代码{{Example|C|D}}
来嵌入包含该模板,那么在Module:ModuleName中,调用frame.args[1]
和frame.args[2]
会返回"A"
和"B"
,调用frame:getParent().args[1]
和frame:getParent().args[2]
则会返回"C"
和"D"
,其中frame
是函数调用的第一个参数。
frame:getTitle
frame:getTitle()
以字符串形式返回与框架关联的标题。对于由{{#invoke:}}
创建的框架,返回被调用的模块的标题。
frame:newChild
frame:newChild{ title = title, args = table }
- 注意使用了命名参数。
创建新的框架对象,该对象是当前框架对象的子对象,可以有可选的参数和标题。
这个主要用于在模块中调用名字由调用方定义的其它模块(例如{{#invoke:params|concat_and_invoke}}
),或在调试控制台测试通常由{{#invoke:}}
调用的函数。一次性可创建的框架的数量是受限制的。
frame:preprocess
frame:preprocess( string )
frame:preprocess{ text = string }
在当前框架环境下展开维基文本,比如,模板、解析器函数以及像{{{1}}}
这样的参数都会展开,然后返回被展开的文本。某些特殊的写成XML格式的标记,比如<pre>
、<nowiki>
、<gallery>
和<ref>
都会被替换为“strip marker”——一类特殊的字符串,由删除符(ASCII 127)开头,在从#invoke
返回后被替换成HTML。
如果你使用单个模板,使用frame:expandTemplate
而非尝试建造维基文本以使用这个方法。这样更快且更不容易出错,尤其是参数包含管道符或其他维基标记时。
同理,展开单个解析器函数时应使用frame:callParserFunction
。
frame:getArgument
frame:getArgument( arg )
frame:getArgument{ name = arg }
获得特定参数的对象,或者没有提供参数时返回nil。
返回的对象有一个方法,object:expand()
,可以返回对应参数的展开后的维基文本。
frame:newParserValue
frame:newParserValue( text )
frame:newParserValue{ text = text }
返回有一个方法object:expand()
的对象,该方法可以返回frame:preprocess( text )
的结果。
frame:newTemplateParserValue
frame:newTemplateParserValue{ title = title, args = table }
- 注意使用了命名参数。
返回有一个方法object:expand()
的对象,该方法可以返回使用给定的参数调用frame:expandTemplate
的结果。
frame:argumentPairs
frame:argumentPairs()
等同于pairs( frame.args )
。考虑到向后兼容。
哈希库
mw.hash.hashValue
mw.hash.hashValue( algo, value )
按照指定的算法算出字符串的哈希值。可以通过mw.hash.listAlgorithms()获得有效的算法。
mw.hash.listAlgorithms
mw.hash.listAlgorithms()
返回支持的哈希算法的列表,以用于mw.hash.hashValue()。
HTML库
mw.html
是用于从Lua构建复杂HTML的流畅接口。许多维基媒体的wiki曾使用Module:HtmlBuilder
实现。mw.html对象可由mw.html.create
创建。
形如mw.html.name
的函数在全局mw.html
表中可用;形如mw.html:name
和html:name
的函数是mw.html对象的方法(参见mw.html.create
)。
一个基础的例子如下所示:
local div = mw.html.create( 'div' )
div
:attr( 'id', 'testdiv' )
:css( 'width', '100%' )
:wikitext( 'Some text' )
:tag( 'hr' )
return tostring( div )
-- Output: <div id="testdiv" style="width:100%;">Some text<hr /></div>
mw.html.create
mw.html.create( tagName, args )
创建一个新的mw.html对象,其包含一个标签名称为tagName
的HTML元素。你也可以传递一个空的字符串或nil作为tagName
以创建一个空的mw.html对象。
args
可以是有以下键的表:
args.selfClosing
:强制当前标签自我闭合,即使mw.html不认为它是自我闭合的args.parent
:当前mw.html实例的上级对象(用于内部使用)
mw.html:node
html:node( builder )
向当前的mw.html实例追加一个mw.html(builder
)子节点。如果传递nil,那么函数不做任何事。(builder
)节点是HTML元素的字符串表示。
mw.html:wikitext
html:wikitext( ... )
给mw.html对象加上不定数量的维基文本字符串。
注意遇到第一个nil项就会停。
诸如HTML、链接、粗体字、列表或表格的基础维基文本会被解析。然而模板和解析器函数在直接传入该函数时不会展开,除非它们来自模板参数。 它们会渲染为纯文本。 如果要展开它们,需要先将它们传入frame:preprocess。
mw.html:newline
html:newline()
给mw.html对象加新行。 mw.html:wikitext()插入的维基文本包含列表或表格之类在一行开头才有意义的语法时,在之前和之后调用该函数会很有用。
mw.html:tag
html:tag( tagName, args )
向建造器追加一个标签名称为tagName
的新子节点,并返回代表这个新节点的mw.html实例。args
参数和mw.html.create
的属性是一样的。
注意,不同于例如html:node()
的其他方法,这个方法不会返回当前的mw.html示例,而是新插入的标签的mw.html示例。
请确保使用html:done()
以获得上级的mw.html示例,或者html:allDone()
以获得多层嵌套标签的最顶级实例。
mw.html:attr
html:attr( name, value )
html:attr( table )
将节点的name
属性的值设为value
。也可以选择用存放名称-值对的表。第一种形式中,如果值为nil,会导致这个给定名称的已被设置属性设为未被设置。
mw.html:getAttr
html:getAttr( name )
获得已经通过html:attr()
设置的属性name
的值。
mw.html:addClass
html:addClass( class )
给节点的类(class)属性添加一个类名称(class name)。如果参数为nil,则无效。
mw.html:css
html:css( name, value )
html:css( table )
将节点的CSS属性name
的值设为value
。也可以选择使用表,其键值对即为CSS名称-值对。第一种形式中,如果值为nil,会导致这个给定名称的已被设置的CSS设为未被设置。
mw.html:cssText
html:cssText( css )
给节点的样式属性添加一些原始css
文本。如果参数为nil,则不做任何事。
mw.html:done
html:done()
返回当前节点被创建时所在的上级节点。类似于jQuery.end,这个方便的函数可以将多个子节点的创建串在一句语句中。
mw.html:allDone
html:allDone()
类似于html:done()
,但是会遍历直到树节点的根部再返回。
语言库
语言代码在语言代码中有描述。很多MediaWiki的语言代码类似于IETF语言标签,但不是所有MediaWiki语言代码都是有效的IETF标签,反之亦然。
形如mw.language.name
的函数在全局mw.language
表可用;形如mw.language:name
和lang:name
的函数是语言对象的方法(参见mw.language.new
或mw.language.getContentLanguage
)。
mw.language.fetchLanguageName
mw.language.fetchLanguageName( code, inLanguage )
给定的语言代码的完整语言名称:默认为本地名称,如有inLanguage
的值,则是被翻译为目标语言的语言名称。
mw.language.fetchLanguageNames
mw.language.fetchLanguageNames()
mw.language.fetchLanguageNames( inLanguage )
mw.language.fetchLanguageNames( inLanguage, include )
获取MediaWiki已知的语言列表,返回将语言代码映射到语言名称的表。
默认返回的名称是语言自称;传递inLanguage
值会返回那个语言下的所有名称。
默认只会返回MediaWiki已知的语言名称,给include
传递'all'
会返回所有可用的语言(例如,从Extension:CLDR 中),传递'mwfile'
会仅包括拥有在MediaWiki核心或启用的扩展包括的自定义消息的语言。如要清楚地选择默认,可以传递'mw'
。
mw.language.getContentLanguage
mw.language.getContentLanguage()
mw.getContentLanguage()
返回wiki当前的默认语言的语言对象。
mw.language.getFallbacksFor
mw.language.getFallbacksFor( code )
返回MediaWiki针对指定语言代码的备选语言代码列表。
mw.language.isKnownLanguageTag
mw.language.isKnownLanguageTag( code )
若语言代码为MediaWiki已知的语言,返回true
。
语言代码“已知”意味着是个“有效的内置代码”(例如,对于mw.language.isValidBuiltInCode
返回true
),对于mw.language.fetchLanguageName
返回一个非空字符串。
mw.language.isSupportedLanguage
mw.language.isSupportedLanguage( code )
检查MediaWiki的语言代码内是否有任何本地化可用。
语言“受支持”意味着是个“有效的”代码(对于mw.language.isValidCode
返回true
),不包含任何大写字母,并在当前运行的MediaWiki版本中有个消息文件。
一个语言代码可能既“受支持”又“未知”(例如,对mw.language.isKnownLanguageTag
返回true
)。还要注意,尽管mw.language.isValidBuiltInCode
返回false
,特定的代码仍是“受支持”的。
mw.language.isValidBuiltInCode
mw.language.isValidBuiltInCode( code )
如果语言代码是用于MediaWiki内部自定义的有效形式,返回true
。
这个代码可能不对应任何已知语言。
语言代码是“有效的内置代码”意味着这是个“有效”代码(比如,对于mw.language.isValidCode
返回true
),只包括ASCII字母、数字和连字符,并至少两个字符长度。
注意有些代码“受支持”(即mw.language.isSupportedLanguage
会返回true
),即使这个函数返回false
。
mw.language.isValidCode
mw.language.isValidCode( code )
若语言代码字符串是有效形式的,返回true
,无论其是否存在。这包括了所有单独用于通过MediaWiki命名空间自定义使用的语言代码。
这个代码可能不对应任何已知语言。
一个语言代码有效意味着不包含任何不安全字符(逗号、单双引号、斜杠、反斜杠、尖括号、连字号或ASCII NUL)且允许出现在页面标题中。
mw.language.new
mw.language.new( code )
mw.getLanguage( code )
创建新的语言对象。语言对象没有任何可公开获取的属性,不过可以含有几个方法,下面列出。
一个页面所使用不同语言代码的数量限制为200个。超过限制会报错。
mw.language:getCode
lang:getCode()
返回这个语言对象的语言代码。
mw.language:toBcp47Code
lang:toBcp47Code()
返回此语言对象的标准BCP-47语言代码。此为适合在HTML中使用的代码字符串,例如作为lang
属性的值。
mw.language:getFallbackLanguages
lang:getFallbackLanguages()
返回MediaWiki针对此语言对象的备选语言代码列表。等同mw.language.getFallbacksFor( lang:getCode() )
。
mw.language:isRTL
lang:isRTL()
若语言是从右至左写的,返回true
,否则返回false
。
mw.language:lc
lang:lc( s )
将字符串转化为小写,但遵从给定的语言的任何特殊规则。
当加载了ustring库,mw.ustring.lower()函数就会通过调用mw.language.getContentLanguage():lc( s )
来实现。
mw.language:lcfirst
lang:lcfirst( s )
将字符串的第一个字符转化为小写,就像lang:lc()
那样。
mw.language:uc
lang:uc( s )
将字符串转化为大写,但遵从给定的语言的任何特殊规则。
当加载了ustring库,mw.ustring.upper()
函数就会通过调用mw.language.getContentLanguage():uc( s )
来实现。
mw.language:ucfirst
lang:ucfirst( s )
将字符串的第一个字符转化为大写,就像lang:uc()那样。
mw.language:caseFold
lang:caseFold( s )
将字符串转换为不区分大小写的比较表示形式。注意,显示其结果可能无任何意义。
mw.language:formatNum
lang:formatNum( n )
lang:formatNum( n, options )
格式化数字,使用给定语言的合适的分组符合小数点。给予123456.78,可能会产生"123,456.78"、"123.456,78"或甚至"١٢٣٬٤٥٦٫٧٨",取决于语言和wiki配置。
options
是包含选项设置的表,可以是:
noCommafy
:若为true
,则省略千位分隔符并使用点号(.
)作为小数点。 数字转化仍会发生,可能包括转化数字分隔符。
mw.language:formatDate
lang:formatDate( format, timestamp, local )
根据给定的格式字符串格式化一个日期。如果省略了timestamp
,默认为当前时间。local
的值必须是boolean或nil,如果是true
,时间会格式化为wiki的当地时间而非UTC。
格式字符串format和timestamp
支持的值与Extension:解析器函數 的#time解析器函数完全相同。
但是要注意,反斜杠可能需要在Lua字符串中写两次,因为Lua也使用反斜杠转义,而维基文本并不:
-- 这个字符串包含新行,不是两个字符"\n",所以不等同于{{#time:\n}}。
lang:formatDate( '\n' )
-- 等同于{{#time:\n}},不是{{#time:\\n}}。
lang:formatDate( '\\n' )
-- 等同于{{#time:\\n}},不是{{#time:\\\\n}}。
lang:formatDate( '\\\\n' )
mw.language:formatDuration
lang:formatDuration( seconds )
lang:formatDuration( seconds, chosenIntervals )
将秒数的时间间隔转化为更加可读的单位,例如12345转化为3小时25分45秒,结果作为字符串返回。
chosenIntervals
如果给定,则应是一个表,其中的值为响应中使用的间隔单位。包括'millennia
'、'centuries
'、'decades
'、'years
'、'weeks
'、'days
'、'hours
'、'minutes
'和'seconds
'。
mw.language:parseFormattedNumber
lang:parseFormattedNumber( s )
这需要一个以lang:formatNum()格式化的数字,并返回实际数字。换句话说,这基本上是tonumber()
能根据语言转换的版本。
mw.language:convertPlural
lang:convertPlural( n, ... )
lang:convertPlural( n, forms )
lang:plural( n, ... )
lang:plural( n, forms )
根据数字n
从forms
(必须是序列表)或...
选择合适的语法形式。例如,在英语你必须使用n .. ' ' .. lang:plural( n, 'sock', 'socks' )
或n .. ' ' .. lang:plural( n, { 'sock', 'socks' } )
来生成语法正确的文本,无论有1只袜子还是200只袜子。
序列的必填值取决于语言,详见魔术字的本地化和translatewiki针对PLURAL的常见问题。
mw.language:convertGrammar
lang:convertGrammar( word, case )
lang:grammar( case, word )
- 注意两个别称之间的不同参数顺序。
convertGrammar
匹配MediaWiki语言对象中同名方法的顺序,而grammar
匹配同名解析器函数的顺序,于帮助:魔术字#本地化有记载。
这会根据给定的屈折代码case
选择word
的合适屈折形式。
word
和case
的可能的值是依赖于语言的,参见Special:MyLanguage/Help:Magic words#Localisation和translatewiki:语法以了解详情。
mw.language:gender
lang:gender( what, masculine, feminine, neutral )
lang:gender( what, { masculine, feminine, neutral } )
选择对应what
的性别的字符串,可以是male、female或注册的用户名。
mw.language:getArrow
lang:getArrow( direction )
返回对应方向direction
的Unicode箭头字符:
- forwards:“→”或“←”,取决于语言的书写方向。
- backwards:“←”或“→”,取决于语言的书写方向。
- left:“←”
- right:“→”
- up:“↑”
- down:“↓”
mw.language:getDir
lang:getDir()
根据语言的书写方向,返回"ltr"(从左至右)或"rtl"(从右至左)。
mw.language:getDirMark
lang:getDirMark( opposite )
返回包含U+200E(从左至右标记)或U+200F(从右至左标记)的字符串,取决于语言的书写方向以及opposite
的值。
mw.language:getDirMarkEntity
lang:getDirMarkEntity( opposite )
返回“‎”或“‏”,取决于语言的书写方向和opposite
的值。
mw.language:getDurationIntervals
lang:getDurationIntervals( seconds )
lang:getDurationIntervals( seconds, chosenIntervals )
将秒数的时间间隔转化为更加已读的单位,例如12345转化为3 hours, 25 minutes and 45 seconds(3时25分45秒),返回从单位名称映射到数字的表。
chosenIntervals
如果给定,则应是一个表,其中的值为响应中使用的间隔单位。包括'millennia
'、'centuries
'、'decades
'、'years
'、'weeks
'、'days
'、'hours
'、'minutes
'和'seconds
'。
这些单元关键字也是响应表中使用的键。响应中仅设置具有非零值的单位,除非响应为空,在这种情况下,返回值为0的最小单位。
系统消息库
这个库是本地化消息和MediaWiki:命名空间的接口。
写成mw.message.name
的函数在全局mw.message
表中可用,写成mw.message:name
和msg:name
的函数是一个消息对象的方法(参见mw.message.new
)。
mw.message.new
mw.message.new( key, ... )
创建一个给定消息key
的新消息对象。
剩下的参数传递到新的对象的params()
的方法。
消息对象没有属性,但是有下面列出的几个方法。
mw.message.newFallbackSequence
mw.message.newFallbackSequence( ... )
从给定的一个或多个消息创建一个新的消息对象(会使用第一个存在的消息)。
消息对象没有属性,但有下面列出的几种方法。
mw.message.newRawMessage
mw.message.newRawMessage( msg, ... )
创建新的消息对象,直接使用给定的文本,而不是查找国际化的消息。剩下的参数会传递到新对象的params()
方法中。
消息对象没有属性,但是有下面列出的几个方法。
mw.message.rawParam
mw.message.rawParam( value )
包装(wrap)该值使之不会被msg:parse()
解析为维基文本。
mw.message.numParam
mw.message.numParam( value )
包装(wrap)该值使之自动被格式化为lang:formatNum()
。注意这不依赖事实上有效的语言库。
mw.message.getDefaultLanguage
mw.message.getDefaultLanguage()
返回默认语言的语言对象。
mw.message:params
msg:params( ... )
msg:params( params )
给消息添加参数,参数可以被传递为独立的参数,或者传递为序列表。参数必须是数字、字符串或由mw.message.numParam()或mw.message.rawParam()返回的特殊的值。如果使用序列表,参数必须是直接出现在表中,使用__index metamethod的引用不起作用。
返回msg
对象,以允许链式调用。
mw.message:rawParams
msg:rawParams( ... )
msg:rawParams( params )
像:params(),但是会先通过mw.message.rawParam()传递所有的参数。
返回msg
对象,以允许链式调用。
mw.message:numParams
msg:numParams( ... )
msg:numParams( params )
像:params(),但是会先通过mw.message.numParam()传递所有的参数。
返回msg
对象,以允许链式调用。
mw.message:inLanguage
msg:inLanguage( lang )
指定一个语言,以在加工消息时使用。lang
可以是字符串,或者带有getCode()
方法的表(比如语言对象)。
默认的语言是由mw.message.getDefaultLanguage()
返回的。
返回msg
对象,以允许链式调用。
mw.message:useDatabase
msg:useDatabase( bool )
指定是否在MediaWiki:命名空间查找消息(比如在数据库中查找),或者只是使用MediaWiki分配的默认消息。
默认为true
。
返回msg
对象,以允许链式调用。
mw.message:plain
msg:plain()
替换参数并按原样返回消息维基文本。模板调用和解析器函数都是完整的。
mw.message:exists
msg:exists()
返回表示消息键是否存在的布尔值。
mw.message:isBlank
msg:isBlank()
返回表示消息键是否有内容的布尔值。当消息键不存在或者消息是空字符串时返回true
。
mw.message:isDisabled
msg:isDisabled()
返回表示消息键是否被禁用的布尔值。如果消息键不存在,或者消息是空字符串,或者是字符串"-"则返回true
。
站点信息库
mw.site.currentVersion
包含当前MediaWiki版本信息的字符串值。
mw.site.scriptPath
mw.site.server
$wgServer
的值。
mw.site.siteName
$wgSitename
的值。
mw.site.stylePath
$wgStylePath
的值。
mw.site.namespaces
包含所有命名空间数据的表,由数字索引。
可用的数据为:
- id: 命名空间数字。
- name: 本地命名空间名称。
- canonicalName: 规范命名空间名称。
- displayName: 为0号命名空间设置的显示名称(由于名字通常是空字符串)。
- hasSubpages: 此命名空间是否启用子页面。
- hasGenderDistinction: 命名空间对不同性别是否拥有不同别名。
- isCapitalized: 命名空间中页面名的首字母是否大写。
- isContent: 此命名空间是否为内容命名空间。
- isIncludable: 此命名空间的页面是否可嵌入。
- isMovable: 此命名空间的页面能否移动。
- isSubject: 此命名空间是否为主题命名空间。
- isTalk: 此命名空间是否为讨论命名空间。
- defaultContentModel: 一个字符串,表示命名空间的默认内容模型。
- aliases: 命名空间的别名列表。
- subject: 指向对应主题命名空间数据的引用。
- talk: 指向对应讨论命名空间数据的引用。
- associated: 指向关联命名空间数据的引用。
设置了元表以便于按照名称(本地化的或者规范的)查找命名空间。比如,mw.site.namespaces[4]
和mw.site.namespaces.Project
都会返回关于Project命名空间的信息。
mw.site.contentNamespaces
只包含内容命名空间的表,按数字索引。参考mw.site.namespaces以了解详细内容。
mw.site.subjectNamespaces
只包含主题命名空间的表,按数字索引。参考mw.site.namespaces以了解详细内容。
mw.site.talkNamespaces
只包含讨论命名空间的表,按数字索引。参考mw.site.namespaces以了解详细内容。
mw.site.stats
包含站点统计的表。可用的统计有:
- pages: wiki中的页面数。
- articles: wiki中的条目数。
- files: wiki中的文件数。
- edits: wiki中的编辑数。
- users: wiki中的用户数。
- activeUsers: wiki中的活跃用户数。
- admins: wiki中“sysop”用户组(即管理员)中的用户数。
mw.site.stats.pagesInCategory
mw.site.stats.pagesInCategory( category, which )
- 这个函数是高开销函数
获得关于分类的统计数据。如果which
拥有指定值"*
",则结果为有如下内容的表:
- all: 页面、文件和子分类的总数。
- subcats: 子分类数。
- files: 文件数。
- pages: 页面数。
如果which
是以上键("all", "subcats", "files", "pages")中的一个,则结果为对应值的数字。
每次新的分类查询都会增大高开销函数次数。
mw.site.stats.pagesInNamespace
mw.site.stats.pagesInNamespace( namespace )
返回给定的命名空间(由数字指定)的页面数量。
mw.site.stats.usersInGroup
mw.site.stats.usersInGroup( group )
返回给定的用户组的用户数量。
mw.site.interwikiMap
mw.site.interwikiMap( filter )
返回包含可用的跨wiki前缀的数据的表。如果filter
是字符串"local",则只会返回关于本地跨wiki前缀的数据。如果filter
是字符串"!local",则只会返回非本地跨wiki前缀的数据。如果没有指定filter,则所有的前缀的数据都会返回。这个"local"前缀是同一个项目的。比如在英文维基百科,其他语言的维基百科都会考虑为本地的(local),而维基词典不会。
这个函数返回的表的键是跨wiki前缀,值是带有以下属性的子表:
- prefix - 跨wiki前缀。
- url - 跨wiki所指向的URL。页面名由$1表示。
- isProtocolRelative - 一个布尔值,表示URL是否使用相对协议。
- isLocal - URL是否为当前项目中的一个网站。
- isCurrentWiki - URL是否为当前wiki。
- isTranscludable - 使用这个跨wiki前缀的页面是否transcludable。这需要吓人的嵌入,此功能在维基媒体的wiki中被禁用。
- isExtraLanguageLink - 跨wiki是否在
$wgExtraInterlanguageLinkPrefixes
中列出。 - displayText - 对于列举在$wgExtraInterlanguageLinkPrefixes中的链接,这是跨语言链接显示的文本。未指定时为nil。
- tooltip - 对于列举在$wgExtraInterlanguageLinkPrefixes中的链接,这是当用户鼠标悬浮在跨语言链接上时显示的工具提示。未指定时为nil。
文本库
文本库提供了一些常见的文本处理函数,这些函数是字符串库和Ustring库中缺少的,并且可用于UTF-8字符串。
mw.text.decode
mw.text.decode( string )
mw.text.decode( string, decodeNamedEntities )
将字符串中的HTML元素替换为对应的字符。
如果布尔值decodeNamedEntities
被省略或者为false,则认可的命名实体只有<
(<), >
(>), &
(&), "
("和
(不换行空格,U+00A0)
否则,认可的HTML5命名实体的列表会从PHP的get_html_translation_table
函数中加载。
已知的bug:在HTML5标准中的大约2,200个命名的实体中,有大约600个不会被解码即使使用了decodeNamedEntities
;这包括HTML4中亦包括了的大约250个实体中的4个。
这是因为PHP的get_html_translation_table
函数为每个字符仅返回一个映射,所以例如
不会被编码,因为PHP只返回→
,因为是→
的映射。
→
mw.text.encode
mw.text.encode( string )
mw.text.encode( string, charset )
使用HTML实体替换字符串中的字符。
五种字符会替换为适当的命名实体:<
、>
、&
、"
和不换行空格(U+00A0)。
所有其他字符都会替换为数字实体。
如果提供了charset
,则它应该是合适的字符串,能直接由Ustring模式的括号括住,比如[set]
中的“set”。默认的charset包括六类字符:<
, >
, &
, "
, '
和不换行空格(U+00A0)。
mw.text.jsonDecode
mw.text.jsonDecode( string )
mw.text.jsonDecode( string, flags )
解码JSON字符串。flags
是0或者mw.text.JSON_PRESERVE_KEYS
和mw.text.JSON_TRY_FIXING
的组合(使用+
)。
通常JSON的数组会被重组到Lua的有键的序列表,如果要避免这个,可以传入mw.text.JSON_PRESERVE_KEYS
。
如果要降低JSON的特定需求,比如数组或对象没有结尾的逗号,可传入mw.text.JSON_TRY_FIXING
。不推荐这样做。
限制:
- 如果数组含有null值,解析的JSON数组可能不是Lua序列。
- JSON对象会丢弃含有null值的键。
- 不能直接分辨带有序列整数键的是JSON数组还是JSON对象。
- 带有序列整数键从1开始的的JSON对象会被解析到作为有相同值的JSON数组的相同的表结构,尽管这些不一定总是相等,除非使用了
mw.text.JSON_PRESERVE_KEYS
。
mw.text.jsonEncode
mw.text.jsonEncode( value )
mw.text.jsonEncode( value, flags )
编码JSON字符串。如果传入的值不能编码为JSON则会报错。flags
是0或者mw.text.JSON_PRESERVE_KEYS
和mw.text.JSON_PRETTY
的组合(使用+
)。
通常Lua中从1开始的序列表会编码成JSON中从0开始的数组;如果flags
中设置了mw.text.JSON_PRESERVE_KEYS
,从0开始的序列表会编码成JSON数组。
限制:
- 空的表总是会被编码为空的数组(
[]
),而不是空的对象({}
)。 - 如果没有加入无效(dummy)元素,序列表不能被编码为JSON对象。
- 如果要产生带有nil值的对象,需要设置
__pairs
元方法。 - 带有从0开始的序列整数键的Lua表会被编码为JSON数组,带有从1开始的整数键的Lua表也是如此,除非使用了
mw.text.JSON_PRESERVE_KEYS
。 - 如果同一个表中,既使用了数字,又使用了代表那个数字的字符串作为键,则行为未指定。
mw.text.killMarkers
mw.text.killMarkers( string )
除去字符串中所有的strip marker。
mw.text.listToText
mw.text.listToText( list )
mw.text.listToText( list, separator, conjunction )
使用自然语言组合一个列表,类似于table.concat()
,但是最后一项前面的分隔符不同。
默认的分隔符取自wiki内容语言的MediaWiki:comma-separator,默认的连词取自由MediaWiki:word-separator连接的MediaWiki:and。
比如,对消息使用默认值:
-- 返回空字符串
mw.text.listToText( {} )
-- 返回"1"
mw.text.listToText( { 1 } )
-- 返回"1和2"(如果wiki的语言设置为“中文”,下同)
mw.text.listToText( { 1, 2 } )
-- 返回"1、2、3、4和5"
mw.text.listToText( { 1, 2, 3, 4, 5 } )
-- 返回"1; 2; 3; 4 or 5"
mw.text.listToText( { 1, 2, 3, 4, 5 }, '; ', ' or ' )
mw.text.nowiki
mw.text.nowiki( string )
使用HTML实体替换字符串中的多种字符,以避免解释为维基文本。包括:
- 以下字符:
"
,&
,'
,<
,=
,>
,[
,]
,{
,|
,}
- 字符串开头或新行后面的的以下字符:
#
,*
,:
,;
, space, tab (\t
) - 空行会使关联的新行与回车字符中的其中一个被转义
- 字符串开始处或新行后的
----
会使得第一个-
被转义 __
会使一个下划线被转义://
会使冒号被转义ISBN
,RFC
或PMID
后的空白字符会被转义
mw.text.split
mw.text.split( string, pattern, plain )
以Ustring模式pattern
为界限,将字符串分割为子串。如果指定了plain
且为true
,则pattern
会被解释为纯字符串而不是Lua模式(就像mw.ustring.find()
的同名参数一样)。返回包含子串的表。
比如,mw.text.split( 'a b\tc\nd', '%s' )
会返回表{ 'a', 'b', 'c', 'd' }
。
如果pattern
匹配空字符串,string
会被分割成单个字符。
注意这个函数可以比不关注Unicode的实现慢60倍以上,如:
function split(text, pattern, plain)
local ret = {}
local s, l = 1, string.len( text )
while s do
local e, n = string.find( text, pattern, s, plain )
if not e then
ret[#ret+1] = string.sub ( text, s )
s = nil
elseif n < e then
-- Empty separator!
ret[#ret+1] = string.sub ( text, s, e )
if e < l then
s = e + 1
else
s = nil
end
else
ret[#ret+1] = e > s and string.sub( text, s, e - 1 ) or ''
s = n + 1
end
end
return ret
end
mw.text.gsplit
mw.text.gsplit( string, pattern, plain )
返回会迭代子字符串的迭代器函数,返回的相当于调用mw.text.split()
。
注意这个函数可以比不关注Unicode的实现慢60倍以上,如:
function gsplit( text, pattern, plain )
local s, l = 1, string.len( text )
return function ()
if s then
local e, n = string.find( text, pattern, s, plain )
local ret
if not e then
ret = string.sub( text, s )
s = nil
elseif n < e then
-- Empty separator!
ret = string.sub( text, s, e )
if e < l then
s = e + 1
else
s = nil
end
else
ret = e > s and string.sub( text, s, e - 1 ) or ''
s = n + 1
end
return ret
end
end, nil, nil
end
mw.text.tag
mw.text.tag( name, attrs, content )
mw.text.tag{ name = string, attrs = table, content = string|false }
- 注意使用了命名参数。
生成name
的HTML样式的标签。
如果给定attrs
,则必须是带有字符串键的表。字符串和数字值会用作属性的值;布尔值true
会使键输出为HTML5的无值参数;布尔值false
会跳过这个键;其他值都会导致报错。
如果没有给出content
(或者是nil),只会返回开始标签。如果content
是布尔值false
,则会返回自我闭合标签。否则它必须是字符串或数字,这样内容就会被开始标签和结束标签包围。注意内容不会自动被编码为HTML;如有需要,使用mw.text.encode()。
对于返回扩展标签的属性,比如<ref>
,应该使用frame:extensionTag()。
mw.text.trim
mw.text.trim( string )
mw.text.trim( string, charset )
从字符串的开始和结尾移除空白字符或其他字符。
如果提供了charset
,则它应该是合适的字符串,能直接由Ustring模式的括号括住,比如[set]
中的"set"。默认的charset是ASCII空白字符,%s
等效于"\t\r\n\f\v "
。
mw.text.truncate
mw.text.truncate( text, length )
mw.text.truncate( text, length, ellipsis )
mw.text.truncate( text, length, ellipsis, adjustLength )
将文本text
按码点截断为指定长度,如果执行了裁剪,则加入ellipsis
。如果长度为正,则字符串末尾被裁剪,如果为负,则字符串的开头会被裁剪。如果给定了adjustLength
且为true
,则包含省略号的字符串不会长于指定的长度。
ellipsis
的默认值取自wiki的内容语言的MediaWiki:ellipsis。
例如,使用默认的"..."省略号:
-- 返回"foobarbaz"
mw.text.truncate( "foobarbaz", 9 )
-- 返回"fooba..."
mw.text.truncate( "foobarbaz", 5 )
-- 返回"...arbaz"
mw.text.truncate( "foobarbaz", -5 )
-- 返回"foo..."
mw.text.truncate( "foobarbaz", 6, nil, true )
-- 返回"foobarbaz",因为比"foobarba..."更短
mw.text.truncate( "foobarbaz", 8 )
mw.text.unstripNoWiki
mw.text.unstripNoWiki( string )
将MediaWiki的<nowiki> strip marker替换为对应的文本。其他类型的strip marker不会改变。
mw.text.unstrip
mw.text.unstrip( string )
等同于mw.text.killMarkers( mw.text.unstripNoWiki( string ) )
。
这个不再显示特殊页面嵌入包含<ref>后的HTML,就像Scribunto早期版本的那样。
标题库
mw.title.equals
mw.title.equals( a, b )
检测两个标题是否相等。注意比较时忽略片段(fragments)。
mw.title.compare
mw.title.compare( a, b )
返回-1, 0或1,表示标题a
是否小于、等于或大于标题b
。
这会按照作为字符串的跨wiki前缀(如果有)比较,然后按命名空间数字,然后按照作为字符串的未加前缀的标题文本比较。字符串比较使用Lua标准的<
操作符。
mw.title.getCurrentTitle
mw.title.getCurrentTitle()
返回当前页面的标题对象。
mw.title.new
mw.title.new( text, namespace )
mw.title.new( ID )
- 用ID调用时该函数是高开销函数
创建新的标题对象。
如果给了ID
,则那个带有那个page_id的页面的对象会被创建。引用的标题会被认为链接到了当前页面。如果page_id不存在,返回nil。如果创建的标题对象不是对于已经加载的标题,则高开销函数数量会被增加。
然而,如果给了字符串text
,那么就会创建那个标题的对象(即使那个页面不存在)。如果文本字符串不指定命名空间,则使用namespace
(可以是在mw.site.namespaces
中找到的任何键)。如果文本不是有效的标题,则会返回nil。
mw.title.makeTitle
mw.title.makeTitle( namespace, title, fragment, interwiki )
创建命名空间namespace
内标题title
的标题对象,可以有指定的片段fragment
和跨wiki前缀interwiki
。namespace
可以是在mw.site.namespaces
中找到的任何键。如果结果的标题无效,返回nil。
注意,不像mw.title.new()
,这个方法总会应用指定的命名空间。比如,mw.title.makeTitle( 'Template', 'Module:Foo' )
会为页面Template:Module:Foo创建对象,而mw.title.new( 'Module:Foo', 'Template' )
会为页面Module:Foo创建对象。
还要注意此功能对于跨wiki的标题仅限于interwiki
/ isExternal
/ isLocal
和与URL有关的方法,可能与预期不同。
标题对象
标题对象有许多属性和方法。大多数属性是只读的。
注意以text
结尾的字段返回作为字符串值的标题,而以title
结尾的字段返回标题对象。
- id:page_id。页面不存在时为
0
。 此属性可能高开销. - interwiki:跨wiki前缀,如果无,则为空白字符串。
- namespace:命名空间数字。
- fragment:片段(也叫段落/锚点连接),或者空字符串。可以赋值。
- nsText:页面的命名空间的文本。
- subjectNsText:页面的主题命名空间的文本。
- talkNsText:页面的讨论命名空间的文本,此标题没有对应的讨论页时则为
nil
。(MediaWiki 1.42.0-wmf.15新增,T180911) - text:页面标题,不含命名空间和跨wiki前缀。
- prefixedText:页面标题,带有命名空间和跨wiki前缀。
- fullText:页面标题,包括命名空间、跨wiki前缀和片段。如果跨wiki等于当前wiki则不返回跨wiki。
- rootText:如果这是子页面,根页面的标题,不带前缀。否则,等同于
title.text
。 - baseText:如果这是子页面,则这个子页面的上级页面的标题,不带前缀。否则,等同于
title.text
。 - subpageText:如果这是个子页面,子页面名称。否则,和
title.text
相同。 - canTalk:这个标题的页面能否拥有讨论页。
- exists:该页面是否存在。Media命名空间页面的
file.exists
别名。对于File命名空间的页面,这将检查文件描述页面的存在,而不是文件本身。此属性可能高开销。 - file,fileExists:参见下面的#文件元数据。
- isContentPage:这个页面是否在内容命名空间内。
- isExternal:此页面是否具有跨wiki的前缀。
- isLocal:此页面是否在此项目中。例如,在英语维基百科上,任何其他语言维基百科都被视为“本地”(Local),而维基字典等则被视为非“本地”。
- isRedirect:是否是重定向页面的标题。此属性可能高开销。
- isSpecialPage:该页面是否可能是特殊页面(即“Special”命名空间中的页面)。
- isSubpage:该页面是否为其他页面的子页面。
- isTalkPage:该页面是否为讨论页。
- isSubpageOf( title2 ):该页面是否为给定页面的子页面。
- inNamespace( ns ):该页面是否在给定的命名空间中。命名空间可以由在
mw.site.namespaces
中定义的任何键指定。 - inNamespaces( ... ):标题是否在给定的命名空间中的任何一个中间。命名空间可以由在
mw.site.namespaces
中定义的任何键指定。 - hasSubjectNamespace( ns ):标题的主题命名空间是否在指定的命名空间内。命名空间必可以由在
mw.site.namespaces
中定义的任何键指定。 - contentModel:此标题的内容模型,字符串,此属性可能高开销。
- basePageTitle:等同于
mw.title.makeTitle( title.namespace, title.baseText )
。 - rootPageTitle:等同于
mw.title.makeTitle( title.namespace, title.rootText )
。 - talkPageTitle:等同于
mw.title.makeTitle( mw.site.namespaces[title.namespace].talk.id, title.text )
,如果该标题没有讨论页则为nil
。 - subjectPageTitle:等同于
mw.title.makeTitle( mw.site.namespaces[title.namespace].subject.id, title.text )
。 - redirectTarget:如果页面是重定向且页面存在,返回重定向页面目标的标题对象,否则返回
false
。 - protectionLevels:页面的保护等级。其值为一个表,键对应每个操作(如
"edit"
、"move"
),值为数组,第一项是包含对应保护等级的字符串,如果页面未被保护,则表的值或者数组的项就会为nil
。此属性高开销。 - cascadingProtection:该页面应用的级联保护,为一个表,键为
"restrictions"
(自身为一个表,键类似于protectionLevels
拥有的那些)和"sources"
(列举保护级联来源的标题的数组)。如果没有保护级联到此页面,则"restrictions"
和"sources"
可能是空的。此属性高开销。 - categories:(自v1.43.0-wmf.18起)页面所使用的分类列表。此属性高开销。
- subPageTitle( text ):等同于
mw.title.makeTitle( title.namespace, title.text .. '/' .. text )
。 - partialUrl():返回编码的
title.text
,就像在URL中会有的那样。 - fullUrl( query, proto )::返回此标题的完整URL(带有可选的查询表或字符串
query
)。可以指定proto以控制返回URL的协议:"http"
,"https"
、"relative"
(默认值)或"canonical"
。 - localUrl( query ):返回此标题的本地的URL(带有可选的查询表或字符串
query
)。 - canonicalUrl( query ):返回此标题的规范URL(带有可选的查询表或字符串
query
)。 - content或getContent():返回页面的(未解析的)内容,如果页面不存在则返回
nil
。页面会被记录为嵌入包含。 - pageLang:标题的页面内容语言(默认为wiki的内容语言)所对应的语言对象。此属性高开销。
标题对象可以使用关系运算符比较。tostring( title )
会返回title.prefixedText
。
请注意获取标题对象的任何高开销的字段会记录一次对页面的“链入”(如Special:WhatLinksHere中所示)。使用标题对象的getContent()
方法或访问redirectTarget
字段会记录为嵌入,访问标题对象的file
或fileExists
字段会记录为"文件链接"。
文件元数据
代表File或Media命名空间下的页面的标题对象会拥有称为file
属性。这是高开销的。这是一个表,其结构如下:
- exists:文件是否存在。会记录一次图像使用。标题对象的
fileExists
属性的存在是为了考虑向后兼容,可以看做该属性的别称。如果这是false
,所有其他属性都会是nil
。 - width:文件宽度。若文件有多个页面,第一页的宽度。
- height:文件的高度。若文件有多个页面,第一页的高度。
- pages:如果文件格式支持多页,这是包含文件每个页面的表,否则为
nil
。“#”操作符可以用于获取文件页数。每个单独的页面表都包含一个width和height属性。 - size:文件的字节长度。
- mimeType:文件的MIME类型。
- length:媒体文件的长度,单位为秒。不支持长度的媒体则为0。
高开销属性
属性id
, isRedirect
, exists
和contentModel
需要从数据库获取标题数据。因此,第一次获取除了当前页面之外的任何页面的这些属性中的一个时,高开销函数数量会增加。之后获取那个页面的这些属性中的任何一个都不会再次增加高开销函数数量。
其他标记为高开销的属性总是会在第一次获取除当前页面之外的页面时增加高开销函数数量。
URI库
mw.uri.encode
mw.uri.encode( string, enctype )
百分号编码字符串。默认类型,"QUERY"
,使用'+'编码空格以用于查询字符;"PATH"
将空格编码为%20,"WIKI"
将空格编码为'_'。
注意"WIKI"格式不是完全可以逆转的,因为空格和下划线都会编码为'_'。
mw.uri.decode
mw.uri.decode( string, enctype )
百分号解码字符串。默认类型,"QUERY"
,将'+'解码为空格;"PATH"
不执行额外的解码,"WIKI"
将'_'解码为空格。
mw.uri.anchorEncode
mw.uri.anchorEncode( string )
编码字符串以用于MediaWiki URI片段。
mw.uri.buildQueryString
mw.uri.buildQueryString( table )
将表编码为URI查询字符串。键必须是字符串,值可以是字符串、数字、序列表或布尔值false。
mw.uri.parseQueryString
mw.uri.parseQueryString( s, i, j )
将查询字符串s
解码为表。字符串中没有值的键会拥有false
值,重复多次的键会有序列表作为其值,其他的都会有字符串作为值。
可选的数字参数i
和j
可以用于指定要解析的s
的子串,而非整个字符串。i
是子串的第一个字符位置,默认为1。j
是子串的最后一个字符位置,默认为字符串长度。i
和j
都可以是负数,就像string.sub那样。
mw.uri.canonicalUrl
mw.uri.canonicalUrl( page, query )
返回页面的规范URL的URI对象,附带可选的查询字符串或表。
mw.uri.fullUrl
mw.uri.fullUrl( page, query )
mw.uri.localUrl
mw.uri.localUrl( page, query )
mw.uri.new
mw.uri.new( string )
利用传入的字符串或表构造一个新的URI对象。参见URI对象的描述以了解表可能的字段。
mw.uri.validate
mw.uri.validate( table )
验证传入的表(或URI对象)是否有效。返回布尔值,以表示表是否有效,以及如果无效,一个描述问题发生原因的字符串。
URI对象
URI对象有以下字段,其中的部分或全部可能是nil:
- protocol:字符串 协议
- user:字符串 用户
- password:字符串 密码
- host:字符串 主机名
- port:整数 端口
- path:字符串 路径
- query:表,就像从mw.uri.parseQueryString中的那样
- fragment:字符串 片段
以下属性也是可用的:
- userInfo:字符串 用户和密码
- hostPort:字符串 主机和端口
- authority:字符串 用户、密码、主机、端口
- queryString::字符串 查询表的字符串版本
- relativePath:字符串 路径、查询字符串、分段
tostring()
会产生URI字符串。
URI对象的方法为:
mw.uri:parse
uri:parse( string )
将字符串解析进当前的URI对象。字符串中指定的任何字段都会替换进当前对象;未指定的字段会保留旧值。
mw.uri:clone
uri:clone()
制作URI对象的拷贝。
mw.uri:extend
uri:extend( parameters )
将参数表合并到对象的查询表。
ustring库
ustring库相当于标准字符串库的重新实现,不过方法会操作于UTF-8编码的字符串的字符,而非字节。
大多数函数会在字符串不是有效的UTF-8时报错,但有例外。
mw.ustring.maxPatternLength
匹配模式(pattern)允许的最大长度,以字节为单位。
mw.ustring.maxStringLength
字符串允许的最大长度,以字节为单位。
mw.ustring.byte
mw.ustring.byte( s, i, j )
返回单独的字节,等同于string.byte()。
mw.ustring.byteoffset
mw.ustring.byteoffset( s, l, i )
返回字符在字符串内的字节偏移值。l
和i
的默认值都是1。i
可以是负数,即倒过来计数。
位于l
== 1的字符是从第i
字节或该字节之后开始的第一个字符,位于l
== 0的字符是从第i
字节或该字节之前开始的第一个字符。注意这可能是同一个字符。更大或者更小的l
值都是相对这些进行计算的。
mw.ustring.char
mw.ustring.char( ... )
非常像string.char(),但是整数为Unicode码位而非字节值。
local value = mw.ustring.char( 0x41f, 0x440, 0x438, 0x432, 0x435, 0x442, 0x21 ) -- 值现在为“Привет!“
mw.ustring.codepoint
mw.ustring.codepoint( s, i, j )
很像string.byte(),但是返回的值是码位,且偏移值为字符而非字节。
mw.ustring.find
mw.ustring.find( s, pattern, init, plain )
非常像string.find(),但是匹配模式是扩展了的,在Ustring patterns中有描述,且init
是按照字符而非字节。
mw.ustring.format
mw.ustring.format( format, ... )
等同于string.format()。字符串的宽度和精度是以字节表达,而非码位。
mw.ustring.gcodepoint
mw.ustring.gcodepoint( s, i, j )
返回用于在字符串内迭代代码点的三个值。i
默认为1,j
默认为-1。这是为了用于for
形式的迭代:
for codepoint in mw.ustring.gcodepoint( s ) do
-- 语句块
end
mw.ustring.gmatch
mw.ustring.gmatch( s, pattern )
非常像string.gmatch(),但是匹配模式是扩展了的,在ustring匹配模式中有描述。
Known bug - When used with a pattern which can match the empty string, the function will get stuck in an infinite loop. For example, the following loop never terminates:
for capture in mw.ustring.gmatch( "foo bar", ".*" ) do
-- block
end
mw.ustring.gsub
mw.ustring.gsub( s, pattern, repl, n )
非常像string.gsub(),但是匹配模式是扩展了的,在ustring匹配模式中有描述。
已知的bug:当repl
是表时,可以使用数字而不是字符串作为键(例如,要替换字符串中所有的
,则键"5"
或[5]
处的值都可被使用);因此,如果这两个键具有不同(非nil)的值,则输出是不可预测的。
问题不影响string.gsub(),它会忽略任何数字作为键的情况。
["5"]
mw.ustring.isutf8
mw.ustring.isutf8( string )
若字符串是有效的UTF-8,返回true
,否则返回false
。
mw.ustring.len
mw.ustring.len( string )
返回字符串的码位长度,或者不是有效的UTF-8时返回nil。
参见string.len()以了解使用字节长度而非码位的类似函数。
mw.ustring.lower
mw.ustring.lower( string )
非常像string.lower(),但是所有在Unicode中定义了小写到大写转换的字符都会被转换。
mw.ustring.match
mw.ustring.match( s, pattern, init )
非常像string.match(),但是匹配模式是扩展了的,在ustring匹配模式中有描述,且init
偏移是按照字符而非字节。
mw.ustring.rep
mw.ustring.rep( string, n )
等同于string.rep()。
mw.ustring.sub
mw.ustring.sub( s, i, j )
非常像string.sub(),但是偏移值为字符而非字节。
mw.ustring.toNFC
mw.ustring.toNFC( string )
将字符串转化为正规形式C(即Normalization Form Canonical Composition)。如果字符串不是有效的UTF-8则返回nil。
mw.ustring.toNFD
mw.ustring.toNFD( s )
将字符串转化为正规形式D(即Normalization Form Canonical Decomposition)。如果字符串不是有效的UTF-8则返回nil。
mw.ustring.toNFKC
mw.ustring.toNFKC( s )
将字符串转化为正规形式KC(即Normalization Form Compatibility Composition)。如果字符串不是有效的UTF-8则返回nil。
mw.ustring.toNFKD
mw.ustring.toNFKD( s )
将字符串转化为正规形式KD(即Normalization Form Compatibility Decomposition)。如果字符串不是有效的UTF-8则返回nil。
mw.ustring.upper
mw.ustring.upper( s )
非常像string.upper(),但是所有在Unicode中定义了大写到小写转换的字符都会被转换。
ustring匹配模式
ustring函数中的匹配模式使用和字符串库匹配模式相同的语法。主要区别是,字符串类会根据Unicode字符属性重新定义。
%a
:代表一般类别“字母”中的所有字符。%c
:代表一般类别“控制”中的所有字符。%d
:代表一般类别“数字、十进制数字”中的所有字符。%l
:代表一般类别“小写字母”中的所有字符。%p
:代表一般类别“标点”中的所有字符。%s
:代表一般类别“分隔符”以及制表符、换行、回车、垂直制表符和换页符中的所有字符。%u
:代表一般类别“大写字母”中的所有字符。%w
:代表一般类别“字母”或“十进制数字”中的所有字符。%x
:加上十六进制数字的全宽字符。
就像在字符串库匹配模式中的那样,%A
, %C
, %D
, %L
, %P
, %S
, %U
, %W
和%X
代表所有补集(不在给定的一般类别内的所有字符)。
在所有情况下,字符串解析为Unicode字符而非字节,所以像[0-9]
这样的范围、%b«»
这样的模式匹配和量词应用在多字节字符时可以正确起作用。空的捕获会捕获码位位置而非字节。
已知限制:与字符串库匹配模式不同,ustring库匹配模式有10,000字节的最大长度限制。匹配模式超出限制会导致ustring函数报错。又由于字符串库匹配模式有自身的32个捕获物的限制(与ustring库不同),如果匹配模式同时超过这两个限制则无法使用,与两个库都不兼容。
注意::9个ASCII字符:$
、+
、<
、=
、>
、^
、`
、|
、~
,可以在字符串库中用%p
匹配,但ustring库中不可以,因为Unicode将这些字符归类为符号而不是标点。
可加载的库
这些库默认不包括,但是如有需要可通过require()
加载。
bit32
这个模拟的Lua 5.2 bit32
库可以用以下的方式加载:
bit32 = require( 'bit32' )
bit32库提供了无符号的32位整数的位运算。输入的整数会被截成整数(方法未指定)并用232模除,这样值就是在0到232-1之间的,返回的值也会是这个范围。
当位有编号时(就像bit32.extract()中那样),0是最低位(带有值20的),31是最高位(带有值231的)。
bit32.band
bit32.band( ... )
返回参数的“按位与”运算:对于结果中的每一位,只有当所有参数中都设置了该位时,结果中才会有这一位。
如果没有给参数,则结果会设置所有位。
bit32.bnot
bit32.bnot( x )
返回x
的“取反”。
bit32.bor
bit32.bor( ... )
返回参数的“按位或”运算:对于结果中的每一位,只要所有参数中有任何一个设置了该位,结果中就会有这一位。
如果没有给参数,则结果会清除所有位。
bit32.btest
bit32.btest( ... )
等同于bit32.band( ... ) ~= 0
bit32.bxor
bit32.bxor( ... )
返回参数的“按位异或”运算:对于结果中的每一位,只有所有参数中设置了该位的参数个数为奇数,结果中才会有这一位。
如果没有给参数,则结果会清除所有位。
bit32.extract
bit32.extract( n, field, width )
从n
导出width
位,以field
为开始。访问0到31范围之外的位都是错误的。
如未指定,width
默认为1。
bit32.replace
bit32.replace( n, v, field, width )
从第field
位元开始,将n
中的width
个位元替换为v
最低的width
个位元。访问0到31范围之外的位元有错误。
如未指定,width
默认为1。
bit32.lshift
bit32.lshift( n, disp )
返回数n
向左移动disp
位。这是一个逻辑移位:插入的位为0。这通常相当于乘以2的disp
次方。
请注意,超过31的位移将导致0。
bit32.rshift
bit32.rshift( n, disp )
返回数n
向右移动disp
位。这是一个逻辑移位:插入的位为0。这通常相当于除以2的disp
次方。
请注意,超过31的位移将导致0。
bit32.arshift
bit32.arshift( n, disp )
返回数n
向右移动disp
位。这是一个算数移位:如果disp
是正的,那么插入的位将会与原始数字的31位相同。
注意超过31的移位将会导致0或4294967295。
bit32.lrotate
bit32.lrotate( n, disp )
返回数n
向左旋转disp
位。
注意旋转位数相当于模32:旋转32位相当于旋转0位,旋转33位相当于旋转1位,以此类推。
bit32.rrotate
bit32.rrotate( n, disp )
返回数n
向右旋转disp
位。
注意旋转位数相当于模32:旋转32位相当于旋转0位,旋转33位相当于旋转1位,以此类推。
libraryUtil
这个库包含一些在实现Scribunto库时有用的方法。它可以用以下的方式加载:
libraryUtil = require( 'libraryUtil' )
libraryUtil.checkType
libraryUtil.checkType( name, argIdx, arg, expectType, nilOk )
type( arg )
不符合预期类型expectType
时报错。此外,如果arg
是nil且nilOk
为true,则不会报错。
name
是调用函数的名称,argIdx
是参数列表中参数的位置。这些用于格式化错误消息。
libraryUtil.checkTypeMulti
libraryUtil.checkTypeMulti( name, argIdx, arg, expectTypes )
type( arg )
不符合预期类型数组expectTypes
中的任何字符串时报错。
用于可以有多个有效类型的参数。
libraryUtil.checkTypeForIndex
libraryUtil.checkTypeForIndex( index, value, expectType )
type( value )
不符合预期类型expectType
时报错。
用于实现__newindex
元方法。
libraryUtil.checkTypeForNamedArg
libraryUtil.checkTypeForNamedArg( name, argName, arg, expectType, nilOk )
type( arg )
不符合预期类型expectType
时报错。此外,如果arg
是nil且nilOk
为true,则不会报错。
在使用Lua的“命名参数”语法(func{ name = value }
)中,此函数用作用等效於libraryUtil.checkType()
。
libraryUtil.makeCheckSelfFunction
libraryUtil.makeCheckSelfFunction( libraryName, varName, selfObj, selfObjDesc )
此函数用于在用于被obj:method()
语法调用的对象表中实现“方法”,会返回一个应该在这些方法顶部调用的函数,并使用self
参数和方法名称,如果self
对象不是selfObject
则会抛出错误。
此函数通常用于库的构造函数中,类似于这样:
function myLibrary.new()
local obj = {}
local checkSelf = libraryUtil.makeCheckSelfFunction( 'myLibrary', 'obj', obj, 'myLibrary object' )
function obj:method()
checkSelf( self, 'method' )
end
function obj:method2()
checkSelf( self, 'method2' )
end
return obj
end
luabit
可用以下的方式来加载luabit库的「bit」和「hex」模块:
bit = require( 'luabit.bit' )
hex = require( 'luabit.hex' )
注意bit32库包含了luabit.bit中的相同操作,luabit.hex也可以使用string.format()
和tonumber()
来运行。
luabit模块noki不可用,因为在Scribunto中完全无用。luabit模块utf8也不可用,因为对Ustring库来说是多余的。
strict
“strict”库不是一个普通的库;每当使用一个新的变量、它並没有被明确地界定为一个局部变量(例如全局变量的赋值引用)时,它就会引起一个错误。这个功能通常是通过在模块的顶部使用下列的方式來加载,而使其致能:
require( 'strict' )
在许多维基媒体的wiki上,这一点以前是在Module:No globals
中实现的(已由phab:T209310替代)。它部分源自strict.lua。
ustring
可以使用下列的方式来加载Ustring库的纯Lua后端:
ustring = require( 'ustring' )
任何情况下,都应该使用Ustring库(mw.ustring
),因为这将取代很多带有PHP代码回调、更慢且消耗内存的操作。
扩展库
一些MediaWiki扩展提供额外的Scribunto库。这些都位于表mw
中,通常是在表mw.text
中,然而,这些只有在安装了特定扩展时才存在(加上Scribunto扩展本身)。
这些扩展使用Scribunto提供的钩子:
Writing Scribunto libraries提供了如何开发这些库以为MediaWiki扩展提供Lua接口的信息。
mw.wikibase
Wikibase客户端 提供了对可本地化的结构数据的访问,尤其是维基数据。 參見docs_topics_lua.html和Extension:Wikibase Client/Lua 。
mw.wikibase.lexeme
WikibaseLexeme 提供了对Wikibase Lexeme实体的访问,由Wikidata:Lexicographical data支持。 參見md_docs_2topics_2lua.html和Extension:WikibaseLexeme/Lua 。
mw.wikibase.mediainfo
WikibaseMediaInfo 提供了对Wikibase MediaInfo实体的访问。 参见WikibaseMediaInfo/Lua 。 这是由Structured Data on Commons支持的,参见Structured data/Lua。
mw.bcmath
BCmath 提供了Lua模块中的任意精度运算,可通过BCmath§用法中的LDoc链接参见BCmath文档。
mw.smw
Semantic Scribunto 提供了对Semantic MediaWiki 扩展的原生Scribunto支持。
mw.ext.data
JsonConfig 提供了对可本地化的表格和地图数据的访问。 参见JsonConfig/Tabular 。 Tabular Data 和GeoJSON 帮助:地图数据 是在Commons的“Data:”命名空间中支持的。
mw.ext.data.get( pagename )
mw.ext.cargo
Cargo 提供了从Lua中查询数据的方法。 参见Extension:Cargo/Other features#Lua support 。
mw.ext.cattools
CategoryToolbox 提供了在Lua中查询某个页面是否属于特定分类的方法。 该扩展是实验性的,在公开的WikiMedia wiki中没有启用。
mw.ext.FlaggedRevs
FlaggedRevs 提供了从Lua中访问页面的稳定性数据的方法。
mw.ext.TitleBlacklist
TitleBlacklist 提供了从Lua中检测黑名单中的页面名称项以及获取有关信息的方法。
mw.ext.ParserFunctions
ParserFunctions 提供了一种来自Lua的手段,以与基于PHP的解析器函数#expr
相同的方式來评估表达式。
mw.ext.proofreadPage
Proofread Page 可以用来访问Index和Page命名空间。 参见Extension:Proofread Page/Lua reference 。 这是由Wikisource:ProofreadPage支持的, 参见Help:Extension:ProofreadPage 。
mw.ext.articlePlaceholder
ArticlePlaceholder 提供了从Lua中覆盖默认的Wikibase渲染的方法, 参见Extension:ArticlePlaceholder/Module:AboutTopic 。
mw.ext.externalData
ExternalData 提供了从Lua中从互联网中获取结构化数据的方法, 参见Extension:External Data/Lua 。
mw.ext.UnlinkedWikibase
mw.ext.UnlinkedWikibase.getEntity( id )
mw.ext.UnlinkedWikibase.query( sparql )
mw.ext.seo
WikiSEO提供了为当前页面获取SEO数据的方法,参见Extension:WikiSEO#Usage in lua modules。
mw.slots
mw.slots.slotContent(slotName, pageName)
mw.slots.slotTemplates(slotName, pageName)
(deprecated)mw.slots.slotContentModel(slotName, pageName)
mw.slots.slotData(slotName, pageName)
与标准Lua的不同之处
改变的函数
以下函数被修改了:
- setfenv()
- getfenv()
- 可能不可用,取决于配置。如果可用,尝试获取上级环境会失败。
- getmetatable()
- 仅应用于表以避免未授权而获取上级环境。
- tostring()
- 不提供表和函数的指针地址。这是为了使得内存侵蚀更难被利用。
- pairs()
- ipairs()
- 支持__pairs和__ipairs元方法(在Lua 5.2中增加的)。
- pcall()
- xpcall()
- 不能拦截某些内部错误。
- require()
- 可以获取Scribunto分发的内置模块,以及在wiki的Module命名空间下存在的模块。如需获取wiki模块,使用包括命名空间的完整页面名称。不能获取本地文件系统。
移除的函数和包
以下包被几乎移除。只有列出来的函数可用。
- package.*
- 文件系统和对C库的取得被移除了。 可用的函数和表为:
- package.loaded
- package.preload
- package.loaders
- 可获取本地文件系统或加载C库的加载器不存在。 添加了Module命名空间页面的加载器。
- package.seeall()
- os.*
- 有些不安全的函数,例如os.execute(),因而不被允许。 可用的函数为:
- debug.*
- 大多数函数都是不安全的。 可用的函数为:
以下函数和包不可用。
- collectgarbage()
- module()
- coroutine.*
- 没有已知的应用,故没有检查安全性。
- dofile()
- loadfile()
- io.*, file.*
- 允许获取本地文件系统,不安全。
- load()
- loadstring()
- 这些被省略了以允许Lua源代码的静态解析。 此外,允许这些会使得Lua代码被直接添加在文章和模板页面,而这不会因为可用性原因被需要。
- print()
- 这在wikitech-l中有讨论,决定省略以支持返回值,以提高代码质量。 如有需要,mw.log()可以用于在调试控制台输出信息。
- string.dump()
- 可能会从上级环境中暴露私有信息。
额外注意事项
- 参考数据结构
- 循环数据结构和同一节点可能通过多条路径到达的数据结构无法正确发送到PHP。 尝试这样做会导致不确定的行为。 这包括(但不限于)从
{{#invoke:}}
调用的模块返回此类数据结构,并将此类数据结构作为参数传递给在PHP中作为回调实现的库函数。
这样的数据结构可以在Lua中自由使用,包括用作通过mw.loadData()加载的模块的返回值
。
编写Scribunto库
此信息对于编写其他Scribunto库的开发者很有用,无论是包含在Scribunto本身还是为他们自己的扩展提供接口。
Scribunto库通常由五个部分组成:
- 库的PHP部分。
- 库的Lua部分。
- 测试用例的PHP部分。
- 测试用例的Lua部分。
- 文档。
现有的库就是一个很好的例子。
库
库的PHP部分必须是继承了Scribunto_LuaLibraryBase
的类。有关实现细节,请参阅该类的文档。在Scribunto扩展中,这个文件应该放在engines/LuaCommon/NameLibrary.php
中,并在Scribunto_LuaEngine::$libraryClasses
中添加一个映射。其他扩展应该使用ScribuntoExternalLibraries钩子。在上述两种中的任何一种情况下,键都应该与Lua模块名称匹配(“mw.name”用于Scribunto中的库,“mw.ext.name”用于扩展库)。
库的Lua部分设置了包含可以从Lua模块调用的函数的表。在Scribunto扩展中,该文件应该放在engines/LuaCommon/lualib/mw.名称.lua
中,通常应包含如下样板文件:
local object = {}
local php
function object.setupInterface( options )
-- 移除setup函数
object.setupInterface = nil
-- 将PHP回调复制到局部变量,并删除全局变量
php = mw_interface
mw_interface = nil
-- 在此处进行任何其他设置
-- 安装到mw全局变量
mw = mw or {}
mw.ext = mw.ext or {}
mw.ext.NAME = object
-- 表示我们已经加载了
package.loaded['mw.ext.NAME'] = object
end
return object
engines/LuaCommon/lualib/libraryUtil.lua
中的模块(使用local util = require 'libraryUtil'
加载此模块)包含一些可能有用的函数。
确保在加载库的情况下运行Scribunto测试用例,即使您的库本身不提供任何测试用例。标准测试用例包括像添加意外全局变量的库之类的测试。此外,如果库是用PHP加载的,其Lua函数所具有的任何上值都不会在#invoke之间重置,必须注意确保模块不能滥用在#invoke之间传输信息。
测试样例
Scribunto扩展包括一个用于测试用例的基类Scribunto_LuaEngineTestBase
,该类将针对LuaSandbox 和LuaStandalone 引擎运行测试。
库的测试用例应该扩展这个类,并且不应该覆盖static function suite()
。
在Scribunto扩展中,测试用例应该在tests/engines/LuaCommon/NameLibraryTest.php
并添加到ScribuntoHooks::unitTestsList()
中的数组中(在common/Hooks.php
中),扩展应该在自己的UnitTestsList
钩子函数中添加测试用例,可能取决于是否设置了$wgAutoloadClasses['Scribunto_LuaEngineTestBase']
。
大多数时候,制作测试用例需要做的包括:
class ClassNameTest extends Scribunto_LuaEngineTestBase { protected static $moduleName = 'ClassNameTest'; function getTestModules() { return parent::getTestModules() + array( 'ClassNameTest' => __DIR__ . '/ClassNameTests.lua'; ); } }
这将加载文件ClassNameTests.lua
,就好像它是页面“Module:ClassNameTests”一样,并期望返回具有以下属性的对象:
- count: 整数,测试次数
- provide(n):函数,返回三个值:
n
,测试n
的名称,以及作为测试预期输出的字符串n
。 - run(n):函数,运行测试
n
并返回一个字符串。
如果getTestModules()
像上面一样被声明,那么“Module:TestFramework”是可以用来提供许多有用的辅助方法,如果使用了,那么ClassNameTests.lua
看起来像这样:
local testframework = require 'Module:TestFramework' return testframework.getTestProvider( { -- 此处放测试 } )
每个测试本身就是一个表,具有以下属性:
- name:测试的名称。
- func:要执行的函数。
- args:传递给函数的可选参数表。
- expect:预期结果。
- type:测试的可选类型,默认为“Normal”。
type控制expect
的格式以及func
的调用方式。包括以下类型:
- Normal:
expect
是返回值的表,但如果测试应该引发错误,则为字符串。func
被简单地调用。 - Iterator:
expect
是返回值的表。func
与迭代for循环一样被调用,并且每次迭代的返回值都会累加。 - ToString:和“Normal”一样,但每个返回值都通过
tostring()
传递。
在其他扩展中的测试样例
有(至少)两种方式来运行PHPUnit测试:
- 针对核心运行phpunit,允许tests/phpunit/suites/ExtensionsTestSuite.php使用UnitTestsList 钩子找到扩展的测试。 如果您的扩展的测试类名称都包含一个唯一的组件(例如扩展的名称),则可以使用
--filter
选项以仅运行您的扩展的测试。 - 对扩展目录运行phpunit,这将获取以“Test.php”结尾的任何文件。
如果在LocalSettings.php中加载了Scribunto,则其中任何一个都可以正常运作。如果未加载Scribunto,那么方法#1很容易生效,因为可以轻松编写UnitTestsList钩子以避免在未设置$wgAutoloadClasses[ 'Scribunto_LuaEngineTestBase' ]
时返回Scribunto测试。
但是Jenkins使用方法#2。为了让Jenkins正确运行测试,您需要将Scribunto添加到扩展的依赖项。有关如何完成此操作的示例,请参见Gerrit change 56570。
如果由于某种原因,您需要能够在不加载Scribunto的情况下使用方法#2运行测试,一种解决方法是将此检查添加到单元测试文件的顶部:
if ( !isset( $GLOBALS['wgAutoloadClasses']['Scribunto_LuaEngineTestBase'] ) ) {
return;
}
帮助文档
Scribunto中包含的模块应该在上面的Scribunto库部分中包含文档。扩展库应该在其自己的扩展页面的子页面中包含文档,并从上方的扩展库章节中链接到该文档。
参见
许可协议
以下内容为译文,请以英文原文为准。
本手册(的英文原文)取自Lua 5.1 参考手册,在MIT许可证下可用。
{{mbox | type = notice | image = none | text = Copyright © 1994–2012 Lua.org,PUC-Rio。
软件著作权持有人据此条款,授权许可任何获得该软件的副本和与其有关的文档文件(“该软件的副本和与其有关的文档文件”以下称为“该软件”)的人,无偿地、不受任何限制(包括使用、复制、修改、合并、出版、分发、再许可和/或销售软件副本的权利)地处理该软件,且可以将该软件提供给他人并对其以同样方式授权许可,但需符合下列条件:
上述著作权声明和本许可声明应包含在所有该软件的副本或带有该软件大部分内容的实体之内。
本软件按“原样”提供,无任何明示或暗示的保证,包括但不限于适销性、特定用途适用性和非侵权性的保证。在任何情况下,作者或版权持有人均不对因本软件或本软件的使用或其他交易而引起的、与之相关的任何索赔、损害赔偿或其他责任负责,无论是合同诉讼、侵权诉讼还是其他诉讼。
本衍生手册也可以根据同一许可证的条款进行复制。