字符串库中的所有函数导出在模块string中。使用时最要采用基于模块的写法,如string.upper(s);
20.1 基础字符串函数
string.len(s) —— 返回字符串s的长度
string.rep(s, a) —— 可返回字符串s重复n次的结果
string.lower(s) —— 返回一份s的副本,将大写字符转换成小写形式
string.upper(s) —— 与string.lowers(s)相反
string.sub(s,i,j) —— 可从字符串中提取第i个到第j个字符。
string.char() —— 接受零个或多个整数,并将每个整数转换成对应的字符,然后返回一个由这些字符连接而成的字符串。
string.byte(s,i) —— 返回字符串s中第i个字符的内部数值表示,第二个参数是可选的,默认字符串s中的第一个字符;
——还可以接受第三个参数如string.byte(s,i,j)可以返回索引i到j之间的所有字符的内部数值;
string.format() —— 用于格式化字符串的利器,经常用在输出上。它会根据第一个参数的描述,返回后续其它参数的格式
——化版本,这第一个参数也称为"格式化字符串"。如:
%.4f表示一个浮点数的小数点后有4个数字
%02d表示一个十进制数至少有两个数字,如不足两个数字则用0补足
%2d表示用空格来补足
20.2 模式匹配函数
字符串库中最强大的函数是find、match、gsub、gmatch、gsub,它们都是基于模式的。
string.find函数用于在一个给定的目标字符串中搜索一个模式。最简单的模式就是一个单词,它只会匹配与自己完全相同的拷贝。
当find找到一个模式后,它会返回两个值:匹配到的起始索引和结尾索引。没有找到任何匹配,它就返回nil;
string.find函数还具有一个可选的第三个参数,它是一个索引,告诉函数应该从目标字符串的哪个位置开始搜索;
string.sub函数用于提取目标字符串中的部分子串,它有三个参数,一个目标字符串,两个整数索引;
string.match函数返回的是目标字符串中与模式匹配的那部分子串,而非该模式所在的位置,如:
date = "Today is 17/7/1990"
d = string.match(date, "%d+/%d+/%d+")
print(d) -->17/7/1990
string.gsub函数有3个参数:目标字符串、模式和替换字符串。它的基本用法是将目标字符串中所有出现模式的地方替换为
替换字符串(最后一个参数):
s = string.gsub("Lua is cute","cute", "great")
print(s) -->Lua is great
另外还有可选的第四个参数,可以限制替换的次数;
函数string.gsub还有另外一个返回值,即实际替换的次数。
string.gmatch函数会返回一个迭代器函数,通过这个函数可以遍历一个字符串中所有出现指定模式的地方。示例——
找出给定字符串s中所有的单词:
words = {}
for w in string.gmatch(s, "%a+") do
words[#words+1]= w
end
通过gmatch和gsub可以模拟出Lua中的require在寻找模块时所用的搜索策略:
function search(modname,path)
modname =string.gsub(modname, "%.", "/")
for c in string.gmatch(path,"[^;]+") do
--遍历path中所有不包含分号的最长子串
local fname = string.gsub(c, "?", modname)
local f =io.open(fname)
if f then
f:close()
return fname
end
end
return nil -- 未找到
end
20.3 模式
字符分类是模式中的一项,可以与特定集合中的任意字符相匹配。
以下是所有的字符分类:
. 所有字符
%a 字母
%c 控制字符
%d 数字
%l 小写字母
%p 标点符号
%s 空白字符
%u 大写字母
%w 字母和数字字符
%x 十六进制数字
%z 内部表示为0的字符
这些分类的大写形式表示它们的补集,例如"%A"表示所有非字母字符:
print(string.gsub("hello, up-down!","%A", "."))--> hello..up.down. 4
(4不是字符串的一部分,而是gsub的第二个结果,即替换的次数)。
模式中还有一些字符被称为魔法字符,它们具有特殊的含义。这些魔法字符有:
( ) . % + - * ? [ ] ^ $
% —— 表示转义字符,但Lua需要用"\"来对引号进行转义在一对方括号内将不同的字符分类或单个字符组合起来,
就可创建出属于自己的字符分类,这种新的字符分类叫做字符集。如"[%w_]"表示同时匹配字母、数字和下划线;
字符集"[01]"表示匹配二进制数字;
在字符集中包含一段字符范围的做法是写出字符范围的第一个字符和最后一个字符,并用横线连接它们。
这个方法用的很少,因为大多数常用的字符范围都预定义好了。
在一个字符集前加一个"^",就可以得到这个字符集的补集;但对于简单的分类,使用大写形式也可以得到其补集。
如"[^0-7]"表示所有非八进制数字的字符。
还可以通过修饰符来描述模式中的重复部分和可选部分。Lua中提供4种修饰符:
+ 重复1次或多次
* 重复0次或多次
- 重复0次或多次
? 可选部分(出现0或1次)
如模式"%a+"表示匹配一个单词;
模式"%d+"表示匹配一个或多个数字(一个整数);
修饰符"*"类似于"+",它还接受出现0次的情况。一种典型的用途是匹配一个模式不同部分之间的空格。
修饰符"-"和"*"一样,也是用于匹配属于字符分类的0个和多个字符。不过它会匹配最短的子串。
修饰符"?"可用于匹配一个可选的字符。例如在一段文本中寻找一个整数,这个整数可以包括一个可选的
正负号。那么可以使用模式"[+-]?%d+"完成这项任务。
如果一个模式以'^'开始,那么它只会匹配目标字符串的开头部分。
如果一个模式以'$'结尾,那么它只会匹配目标字符串的结尾部分。
这些标记可用于限定一个模式的查找。如string.find(s, "^[+-]?%d+$")则可检查这个字符串是否表示一个整数,
并且没有多余的前导字符和结尾字符。
在模式中还可以使用"%b",用于匹配成对的字符。它的写法是"%b<x><y>",这种模式的典型用法包括"%b()",
"%b[]","%b<>"等等,但实际上可以用任何字符作为分隔符。
20.4 捕获
捕获功能可根据一个模式从目标字符串中抽出匹配于该模式的内容。在指定捕获时,应将模式中需要捕获的
部分写到一对圆括号内。
对于具有捕获的模式,函数string.match会将所有捕获到的值作为单独的结果返回;即它会将目标字符串切成
多个捕获到的部分:
pair = "name = Anna"
key, value = string.match(pair,"(%a+)%s*=%s*(%a+)")
print(key, value) -->name value
date = "Today is 17/7/1990"
d, m, y = string.match(date,"(%d+)/(%d+)/(%d+)")
print(d, m, y) -->17 7 1990
20.5 替换
string.gsub函数的第三个参数不仅是一个字符串,还可以是一个函数或table。
当用一个函数来调用时,string.gsub会在每次找到匹配时调用该函数,调用时的参数就是捕获到的内容,
而该函数的返回值则作为要替换的字符串;
当用一个table来调用时,string.gsub会用每次捕获到的内容作为key,在table中进行查找,并将对应的value
作为要替换的字符串。如果table中不不含这个key,那么string.gsub不改变这个匹配。示例——
function expand(s)
return string.gsub(s, "$(%w+)",_G)
end
name = "Lua"; status = "great"
print(expand("$name is $status, isn'tit?"))
--> Lua is great, isn't it?
如果不确定所有的变量都有一个对应的字符串值,则可以对它们的值应用tostring。
在这种情况下,可以用一个函数来提供要替换的值:
function expand(s)
return (string.gsub(s,"$(%w+)",
function(n) return tostring(_G[n]) end))
end
print(expand("print =$print; a = $a"))
--> print =function: 0x8050ce0; a = nil
其它模式和技巧,暂不掌握,需要时查看P178;