03-字符串

争取两三周入门Lua!

Lua语言中的字符串既可以表示单个字符,也可表示一整本书长的字符。Lua语言中的字符串是一串字节组成的序列,它不关心字符的编码,每个字符使用8位存储。

Lua中的字符串是 不可变值,这说明我们不能直接改变某字符串的某个字符,应该再创建一个新的字符串来达到“修改”的目的:

a = "one string"
b = string.gsub(a, "one", "another")	-- 把a中的"one"改成"another"

像Lua语言中的其他对象(表、函数等)一样,Lua的字符串也是自动内存管理的对象之一,开发人员无需关注。

字符串常量

可以用一对双引号或单引号来声明字符串常量,用单引号声明的常量不用转义双引号;用双引号声明的常量不用转义单引号。

a = "line"
b = 'another line'

转义字符

常见C风格转义字符如下:

转义字符释义
\a响铃
\b退格
\f换页
\n换行
\r回车
\t水平制表符
\v垂直制表符
\\反斜杠
\"双引号
\'单引号

除此之外,还能通过形如\ddd\xhh的转义序列来声明字符,前者是用3个10进制表示,后者是用2个16进制表示。从Lua5.3开始,也能用转义序列\u{h...h}来声明UTF-8字符。

字符串操作符

可以用 长度操作符# 获取字符串的长度:

a = "hello"
#a			--> 5
#"good bye"	--> 8

可以用 连接操作符..来进行字符串连接:

"Hello " .. "World"		--> Hello World
"res = " .. 3			--> res = 3

长字符串/多行字符串

像多行注释一样,也能用一堆双括号来声明多行字符串:

page = [[
<html>
	<body> hello </body>
</html>
]]

如果字符串内部也有[[]],可以通过在括号间加入=进行区分:[==[xxx]==],长注释也能这样做。

强制类型转换

Lua在运行时提供了数值类型与字符串类型之间的自动转换,针对字符串的所有算术操作都会尝试将字符串转换为数值。同理,当Lua发现在需要字符串的地方出现数值时,也会尝试将数值转换为字符串。

除此之外,可以用函数tonumber()将字符串转换为数值,用函数tostring()将数值转换为字符串。

tonumber("    -3 ")		--> -3
tonumber("fff", 16)		--> 4095
tostring(10) == "10"	--> true

字符串标准库

Lua语言处理字符串的完整能力来自其字符串标准库。

常用库函数

string.len(s)

返回字符串s的长度,等价于#。

string.rep(s, n)

返回字符串s重复n次的结果。

string.reverse(s)

返回将字符串s翻转后的结果。

string.lower(s)

返回将字符串s的小写版本。

-- 忽略大小写比较字符串
string.lower(a) < string.lower(b)

string.upper(s)

返回将字符串s的大写版本。

string.sub(s, i, j)

返回字符串s的字串,范围是[i, j],其中字符串的第一个索引为1。索引可以是负数,此时它代表倒数第x个字符。

string.char(i, …)

接收若干整数作为参数,然后将每个整数转换为对应的字符,最后返回由这些字符连接而成的字符串。

string.char(99, 100, 101)	--> cde

string.byte(s, i, j)

返回字符串s中区间[i, j]的字符的数值:

string.byte("abc", -1)		--> 99

当字符串不大时(不超过1MB),可以用{string.byte(s, 1, -1)}将字符串s中所有字符转换为所有字符数值组成的表,因为栈大小有限制,限制了该函数的返回值,因此最大为一百万个字符数值。

格式化输出

string.format()

是用于进行字符串格式化和将数值格式化输出为字符串的强大工具,该函数会返回第一个参数(格式化字符串)的副本,其中的每一个指示符都会被替换为使用对应格式进行格式化后的对应参数。使用和C语言的printf()类似:

string.format("x = %d	y = %d", 10, 20)		-->	x = 10	y = 20
string.format("x = 0x%X", 200)					--> x = 0xC8
tag, title = "h1", "a title"
string.format("<%s>%s</%s>", tag, title, tag)	--> <h1>a title</h1>

模式匹配

string.find()

用于在指定的字符串中进行模式搜索:

string.find("hello world", "wor")	--> 7	 9
string.find("hello world". "war")	--> nil

如果找到了,会返回开始和结束位置;找不到则返回nil

string.gsub()

把所有匹配到的模式用另一个字符串替换:

string.gsub("hello world", "l", ".")	--> he..o wor.d	 3
string.gsub("hello world", "a", ".")	--> hello world	 0

返回“修改”后的字符串,然后还返回替换的次数。

冒号操作符

如果s是一个字符串,那么可以用 冒号操作符: 调用字符串的任意方法:

s:sub(i, j)		--> string.sub(s, i, j)

Unicode编码

从Lua5.3开始,Lua语言引入了一个用于操作UTF-8编码的Unicode字符串的标准库。UTF-8使用变长的多个字节来编码一个Unicode字符。例如,UTF-8使用一个字节的65来代表A,使用两个字节的215-144代表希伯来语字符Aleph。

因为函数reverse,upper,lower,byte,char针对单字节字符处理,所以这些函数不能用于处理UTF-8字符串。而Lua提供了utf8库来解决这些函数无法使用的问题。

utf8库

在utf8库中:

  • utf8.len()string.len()类似,不过它返回的是UTF-8字符的代码点个数,如果有无效字符,会返回nil和无效字符位置。
  • utf8.char()utf8.codepoint()在UTF-8环境下等价于string.char()string.byte()
  • 需要注意的是,utf8库中 大多数函数使用字节作为索引,而不是字符位置。如果要用字符位置作为索引,需要用utf8.offset(s, i)获取第i个字符的字节位置。
  • 使用utf8.codes()获取UTF-8字符串所有字符的字节位置与内容,从而容易遍历。

如果要支持其他特殊需求,得使用外部库。