Lua
语言解释器本身处理字符串的能力是十分有限的。一个程序能够创建字符串、连接字符串、比较字符串和获取字符串长度,但是,它并不能提取字符串的子串或检视字符串的内容。 Lua
语言处理字符串的完整能力来自其字符串标准库。
字符串标准库默认处理的是 8 bit
( 1 byte
)字符。这对于某些编码方式(例如 ASCII
或 ISO-8859-1
)适用,但对所有的 Unicode
编码来说都不适用。不过尽管如此,字符串标准库中的某些功能对 UTF-8
编码来说还是非常有用的。
简单函数
字符串标准库中的一些函数非常简单:函数 string.len(s)
返回字符串 s
的长度,等价于 #s
。函数 string.rep(s, n)
返回字符串 s
重复 n
次的结果。可以通过调用 string.rep("a", 2^20)
创建一个 1MB
大小的字符串(例如用于测试)。函数 string.reverse
用于字符串反转。函数 string.lower(s)
返回一份 s
的副本,其中所有的大写字母都被转换成小写字母,而其他字符则保持不变。函数 string.upper
与之相反,该函数会将小写字母转换成大写字母。
> string.rep("abc", 3) --> abcabcabc > string.reverse("A Long Line!") --> !eniL gnoL A > string.lower("A Long Line!") --> a long line! > string.upper("A Long Line!") --> A LONG LINE!
作为一种典型的应用,我们可以使用如下代码在忽略大小写差异的原则下比较两个字符串:
string.lower(a) < string.lower(b)
string.sub(s, i, j)
函数 string.sub(s, i, j)
从字符串s中提取第 i
个到第 j
个字符(包括第 i
个和第 j
个字符,字符串的第一个字符索引为 1
)。该函数也支持负数索引,负数索引从字符串的结尾开始计数:索引 -1
代表字符串的最后一个字符,索引 -2
代表倒数第二个字符,以此类推。这样,对字符串 s
调用函数 string.sub(s, 1, j)
得到的是字符串 s
中长度为 j
的前缀,调用 string.sub(s, j, -1)
得到的是字符串 s
中从第 j
个字符开始的后缀,调用 string.sub(s, 2, -2)
返回的是去掉字符串是中第一个和最后一个字符后的结果:
> s = "[in brackets]" > string.sub(s, 2, -2) --> in brackets > string.sub(s, 1, 1) --> [ > string.sub(s, -1, -1) --> ]
注意
Lua
语言中的字符是不可变的。和 Lua
语言中所有其他函数一样,函数 string.sub
不会改变原有字符串的值,它只会返回一个新字符串。一种常见的误解是以为 string.sub(s, 2, -2)
返回的是修改后的 s
。如果需要修改原字符串,那么必须把新的值赋给它:
s = string.sub(s, 2, -2)
string.char 和 string.byte
函数 string.char
和 string.byte
用于转换字符串及其内部数值表示。函数 string.char
接收 0
个或多个整数作为参数,然后每个整数转换成对应的字符,最后返回由这些字符连接而成的字符串。函数 string.byte(s, i)
返回字符串 s
中第 i
个字符的内部数值表示,该函数的第二个参数是可选的。调用 string.byte(s)
返回字符串 s
中第一个字符(如果字符串只由一个字符组成,那么就返回这个字符)的内部数值表示。在下例中,假定字符是用 ASCII
表示的:
> print(string.char(97)) --> a > i = 99; print(string.char(i, i+1, i+2)) --> cde > print(string.byte("abc")) --> 97 > print(string.byte("abc", 2)) --> 98 > print(string.byte("abc", -1)) --> 99
在最后一行中,使用负数索引来访问字符串的最后一个字符。
调用 string.byte(s, i, j)
返回索引 i
到 j
之间(包括 i
和 j
)的所有字符的数值表示:
> print(string.byte("abc", 1, 2)) --> 97 98
一种常见的写法是 {string.byte(s, 1, -1)}
,该表达式会创建一个由字符串 s
中的所有字符代码组成的表。
提示
由于 Lua
语言限制了栈大小,所以也限制了一个函数的返回值的最大个数,默认最大为一百万个。因此,这个技巧不能用于大小超过 1MB
的字符串。
string.format
函数 string.format
是用于进行字符串格式化和将数值输出为字符串的强大工具,该函数会返回第一个参数(也就是所谓的格式化字符串)的副本,其中的每一个指示符( directive
)都会被替换为使用对应格式进行格式化后的对应参数。格式化字符串中的指示符与C语言中函数 printf
的规则类似,一个指示符由一个百分号和一个代表格式化方式的字母组成: d
代表一个十进制整数、 x
代表一个十六进制整数、 f
代表一个浮点数、 s
代表字符串,等等。
> string.format("x = %d y = %d", 10, 20) --> x = 10 y = 20 > string.format("x = %x", 200) --> x = c8 > string.format("x = 0x%X", 200) --> x = 0xC8 > string.format("x = %f", 200) --> x = 200.000000 > tag, title = "h1", "a title" > string.format("<%s>%s</%s>", tag, title, tag) --> <h1>a title</h1>点击复制复制失败已复制
在百分号和字母之间可以包含用于控制格式细节的其他选项。例如,可以指定一个浮点数中小数的位数:
> print(string.format("pi = %.4f", math.pi)) --> pi = 3.1416 > d = 5; m = 11; y = 1990 > print(string.format("%02d/%02d/%04d", d, m, y)) --> 05/11/1990
在上例中, %.4f
表示小数点后保留 4
位小数; %02d
表示一个十进制数至少由两个数字组成,不足两个数字的用 0
补齐,而 %2d
则表示用空格来补齐。关于这些指示符的完整描述可以参阅C语言printf
函数的相关文档,因为 Lua
语言是通过调用C语言标准库来完成实际工作的。
简化写法
可以使用冒号操作符像调用字符串的一个方法那样调用字符串标准库中的所有函数。例如, string.sub(s, i, j)
可以重写为 s:sub(i, j)
, string.upper(s)
可以重写为 s:upper()
。
模式匹配函数
字符串标准库还包括了几个基于模式匹配的函数。函数 string.find
用于在指定字符串中进行模式搜索:
> string.find("hello world", "wor") --> 7 9 > string.find("hello world", "war") --> nil
如果该函数在指定字符串中找到了匹配的模式,则返回模式的开始和结束位置,否则返回 nil
。函数 string.gsub
(Global SUBstitution)则把所有匹配的模式用另一个字符串替换:
> string.gsub("hello world", "l", ".") --> he..o wor.d 3 > string.gsub("hello world", "ll", "..") --> he..0 world 1 > string.gsub("hello world", "a", ".") --> hello world 0
该函数还会在第二个返回值中返回发生替换的次数。