Skip to content

6.4 - 字符串操作

此库提供了字符串操作的通用函数,例如查找和提取子串,或是模式匹配。在Lua中对字符串使用索引时,第一个字符的位置是1(而不是像C代码中的0)。索引可以是负数,以表示从末尾开始倒数的下标。例如最后一个字符的位置是-1,以此类推。

字符串库所提供的函数都放在名为 string 的表中。其同时会设置字符串值的元表,其中 __index 字段指向了 string 表。因此你可以使用面向对象的风格来调用字符串函数。例如 string.byte(s,i) 可以写成 s:byte(i) 的形式。

字符串库中,字符是假定为单字节编码的。

string.byte (s [, i [, j]])

返回字符串中索引 i 到索引 j 之间的(s[i], s[i+1], ..., s[j]) 的各个字符的数值。参数 i 的默认值为1,j 的默认值为 i 的值。此处遵循和string.sub中一样的索引规则。

其由字符转换而来的数值在各平台之间不一定都相同。

string.char (···)

接收零个或多个整数参数。返回一个字符串,其长度为传入的参数数量,其中每个字符依次为各参数在内部字符编码中所对应的字符。

其中的编码数值在各平台之间不一定都相同。

string.dump (function [, strip])

返回包含所给函数的二进制表示(即二进制块 binary chunk )的字符串,之后对该字符串调用load会返回该函数的拷贝(但是其上值都是新创建的)。如果参数 strip 为真值,那么其二进制块中将不会把该函数所有的调试信息都包含进去,由此可以节省空间。

对于带有上值的函数,二进制块只会存储其上值的数量。被(再次)加载后,这些上值都会是新实例。(相关细节请参见load函数。必要时你可以使用调试库来序列化或重新加载这些函数的上值。)

string.find (s, pattern [, init [, plain]])

在字符串 s 中查找 pattern 参数的第一个匹配(参见6.4.1)。如果找到了,那么 find 函数会分别返回匹配位置的开始和结束索引;否则返回fail。第三个可选参数 init 表明从哪里开始搜索,其默认值为1并且可以是负数。第四个参数 plain 为treu时会关闭模式匹配机制,从而做直接“查找子串”的操作,参数 pattern 中内容都视为无特殊含义的字符。

如果匹配式 pattern 捕获到了,则表示匹配成功并且会在两个索引后一并返回捕捉到的值。

string.format (formatstring, ···)

第一个参数必须为字符串,后边跟不定数量的参数,返回所组成的格式化字符串。这里的字符串格式化规则与ISO标准C函数 sprintf 相同。但是不支持转义符 F、n、*、h、L、和 l ,并且多出一个额外的转义符 q 。如果有宽度和精度,则限制为两位数。

转义符对布尔、nil、number和字符串的转移结果都是一个定义在Lua源码中的有效常量值。布尔和 nil 的结果都是直接写在代码中的(true、false、nil)。浮点数结果为一个十六进制数,以保证完整精度。字符串的转换结果会被放在双引号之间,会在必要的时候使用合适的转义符,此结果可以在之后供Lua解释器成功读入。例如这样的调用:

lua
string.format('%q', 'a string with "quotes" and \n new line')

会生成这样的字符串:

"a string with \"quotes\" and \
new line"

该转义符不支持修饰符(如标志、宽度、精度)。

转义符 A、a、E、e、f、G、以及 g 都需要一个数字作为参数。转义符 c、d、i、o、u、X、以及 x 需要的是整数。当Lua是由C89标准编译出时,转义符 A 和 a (十六进制浮点数) 都不支持修饰符。

转义符 s 需要一个字符串作为参数,如果传入的参数不是个字符串,那么其将遵循和tostring相同的规则转换为一个字符串。如果该转义符有任何修饰符,则对应的字符串参数不应当包含任何嵌入的零。

转义符 p 会使用lua_topointer来格式化指针。其会给出一个可以唯一标识表、userdata 、Lua线程、字符串和函数的字符串。对于其他类型的值(number、nil、布尔值),转义符将返回表示空指针的字符串。

string.gmatch (s, pattern [, init])

返回一个迭代器函数,每次调用该迭代器函数都会返回下一个在字符串 s 中对 pattern 的捕获(参见6.4.1)。如果 pattern 没有指定的捕获,那么每次调用就匹配整个 pattern 内容。第三个参数 init 是可选的数字,其表明匹配的起始位置,默认为1且可以传负数。

举个例子,以下这个循环将迭代字符串中的每个单词,并分行打印出来:

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

下边的例子会将给定字符串中的每个键值对收集起来:

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

对于此函数,pattern 开头中的锚点 '^' 将不会生效,因为其会阻止迭代。

string.gsub (s, pattern, repl [, n])

拷贝整个字符串 s (或者前 n 个,如果传了此参数的话),将其中每个遇到的 pattern 匹配和捕获(参见6.4.1)根据 repl 来做替换,并将最终的字符串返回。参数 repl 可以是字符串、表、或者函数。同时 gsub 会将遇到的匹配次数作为第二个返回值返回。函数名 gsub 出自全局替换 Global SUBstitution

如果参数 repl 是一个字符串,那么其值将被用来做替换。"%" 符为转义符:任何包含在 repl 中的 %d 都被认为是第 d 个捕获项,其中 d 的值可以是1到9,%0 表示整个捕获项,%% 表示单个 "%" 符。

如果 repl 是个表,则每次匹配时都会使用捕获中的第一个捕获项作为键来对该表作查询。

如果 repl 是个函数,则每次匹配时都会将所有的捕获项先后作为参数传入来调用该函数。

如果从 repl 表或函数中得到的返回是一个字符串或 number ,那么其将会被作为替换用的字符串。否则如果返回的是nil或者false,那么将不会做替换(即原匹配维持原样)。

以下是部分示例:

lua
x = string.gsub("hello world", "(%w+)", "%1 %1")
--> x="hello hello world world"

x = string.gsub("hello world", "%w+", "%0 %0", 1)
--> x="hello hello world"

x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
--> x="world hello Lua from"

x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
--> x="home = /home/roberto, user = roberto"

x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
      return load(s)()
    end)
--> x="4+5 = 9"

local t = {name="lua", version="5.4"}
x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
--> x="lua-5.4.tar.gz"

string.len (s)

接收一个字符串参数并返回其长度。空串 "" 的长度为0。嵌入的零值也会被计数,所以 "a\000bc\000" 的长度为5。

string.lower (s)

接收一个字符串参数并拷贝它(不会改动原有的字符串),将其中每个大写的字符都替换为对应的小写形式,将最终的字符串返回。其他的字符都不会被更改。对于大写字母的定义取决于当前的区域设置。

string.match (s, pattern [, init])

在字符串 s 中查找 pattern 的第一个匹配(参见6.4.1)。如果找到了,match 会将 pattern 的捕获返回;否则返回 fail。如果 pattern 不含有捕获内容,那么将返回整个 pattern 的匹配。第三个参数 init 是一个可选数字参数,其表明搜索的起始位置;默认值为1且可以为负值。

string.pack (fmt, v1, v2, ···)

返回一个包含了 v1、v2等值的二进制字符串,该字符串是通过格式化字符串 fmt 序列化而来的(参见6.4.2)。

string.packsize (fmt)

返回string.pack的结果的长度。该格式化字符串不可以包含变长的选项 's' 或 'z' (参见6.4.2)。

string.rep (s, n [, sep])

返回一个字符串,其由字符串 s 的 n 个拷贝组成,每个拷贝之前用 sep 间隔开。参数 sep 的默认值为空串(即没有间隔)。如果参数 n 不为正数则返回空串。

(要注意该函数很容易耗尽你的内存。)

string.reverse (s)

返回所给字符串 s 的翻转。

string.sub (s, i [, j])

截取字符串 s 从第 i 个到第 j 个字符并返回;其中 i 和 j 可以是负数。如果 j 缺省,则会被当作 -1 处理(即字符串末尾)。例如,调用 string.sub(s,1,j) 会返回 s 中前 j 个字符,而 string.sub(s, -i) (i为整数)则返回 s 中后 j 个字符。

在转换完负数索引后,如果 i 小于1,则置为1,如果 j 大于字符串长度,则置为字符串长度。在此之后,如果 i 大于 j ,该函数会返回一个空串。

string.unpack (fmt, s [, pos])

返回以格式化字符串 fmt 打包(参见string.pack)而来的二进制字符串 s 中的值。可选参数 pos 标记了在 s 中读取的起始位置。读取完这些值后,该函数同时还返回在 s 中第一个不可读字节的位置。

string.upper (s)

接收一个字符串参数并拷贝它(不会改动原有的字符串),将其中每个小写的字符都替换为对应的大写形式,将最终的字符串返回。其他的字符都不会被更改。对于小写字母的定义取决于当前的区域设置。