4. 标准库

最后更新于:2022-04-01 23:21:56

## String ~~~ string.byte string.char string.dump string.find string.format string.gmatch string.gsub string.len string.lower string.match string.rep string.reverse string.sub string.upper ~~~ > 在string库中功能最强大的函数是:string.find(字符串查找),string.gsub(全局字符串替换),and string.gfind(全局字符串查找)。这些函数都是基于模式匹配的。 > > 与其他脚本语言不同的是,Lua并不使用POSIX规范的正则表达式(也写作regexp)来进行模式匹配。主要的原因出于程序大小方面的考虑:实现一个典型的符合POSIX标准的regexp大概需要4000行代码,这比整个Lua标准库加在一起都大。权衡之下,Lua中的模式匹配的实现只用了500行代码,当然这意味着不可能实现POSIX所规范的所有更能。然而,Lua中的模式匹配功能是很强大的,并且包含了一些使用标准POSIX模式匹配不容易实现的功能。 ### [](https://github.com/andycai/luaprimer/blob/master/04.md#1-pattern-模式)(1) pattern 模式 下面的表列出了Lua支持的所有字符类: ~~~ . 任意字符 %a 字母 %c 控制字符 %d 数字 %l 小写字母 %p 标点字符 %s 空白符 %u 大写字母 %w 字母和数字 %x 十六进制数字 %z 代表0的字符 ~~~ 可以使用修饰符来修饰模式增强模式的表达能力,Lua中的模式修饰符有四个: ~~~ + 匹配前一字符1次或多次 * 匹配前一字符0次或多次 - 匹配前一字符0次或多次 ? 匹配前一字符0次或1次 ~~~ '%b' 用来匹配对称的字符。常写为 '%bxy' ,x和y是任意两个不同的字符;x作为匹配的开始,y作为匹配的结束。比如,'%b()' 匹配以 '(' 开始,以 ')' 结束的字符串: ~~~ print(string.gsub("a (enclosed (in) parentheses) line", "%b()", "")) --> a line ~~~ 常用的这种模式有:'%b()' ,'%b[]','%b%{%}' 和 '%b<>'。你也可以使用任何字符作为分隔符。 ### [](https://github.com/andycai/luaprimer/blob/master/04.md#2-capture-捕获)(2) capture 捕获 Capture是这样一种机制:可以使用模式串的一部分匹配目标串的一部分。将你想捕获的模式用圆括号括起来,就指定了一个capture。 ~~~ pair = "name = Anna" _, _, key, value = string.find(pair, "(%a+)%s*=%s*(%a+)") print(key, value) --> name Anna ~~~ ### [](https://github.com/andycai/luaprimer/blob/master/04.md#3-stringfind-字符串查找)(3) string.find 字符串查找 string.find 的基本应用就是用来在目标串(subject string)内搜索匹配指定的模式的串,函数返回两个值:匹配串开始索引和结束索引。 ~~~ s = "hello world" i, j = string.find(s, "hello") print(i, j) --> 1 5 print(string.sub(s, i, j)) --> hello print(string.find(s, "world")) --> 7 11 i, j = string.find(s, "l") print(i, j) --> 3 3 print(string.find(s, "lll")) --> nil ~~~ string.find函数第三个参数是可选的:标示目标串中搜索的起始位置。 在string.find使用captures的时候,函数会返回捕获的值作为额外的结果: ~~~ pair = "name = Anna" _, _, key, value = string.find(pair, "(%a+)%s*=%s*(%a+)") print(key, value) --> name Anna ~~~ 看个例子,假定你想查找一个字符串中单引号或者双引号引起来的子串,你可能使用模式 '["'].-["']',但是这个模式对处理类似字符串 "it's all right" 会出问题。为了解决这个问题,可以使用向前引用,使用捕获的第一个引号来表示第二个引号: ~~~ s = [[then he said: "it's all right"!]] a, b, c, quotedPart = string.find(s, "(["'])(.-)%1") print(quotedPart) --> it's all right print(c) --> " ~~~ ### [](https://github.com/andycai/luaprimer/blob/master/04.md#4-stringgmatch-全局字符串查找)(4) string.gmatch 全局字符串查找 string.gfind 函数比较适合用于范性 for 循环。他可以遍历一个字符串内所有匹配模式的子串。 ~~~ words = {} for w in string.gmatch("nick takes a stroll", "%a+") do table.insert(words, w) end ~~~ **URL解码** ~~~ function unescape(s) s = string.gsub(s, "+", " ") s = string.gsub(s, "%%(%x%x)", function(h) return string.char(tonumber(h, 16)) end) return s end print(unescape("a%2Bb+%3D+c")) -- a+b = c ~~~ 对于name=value对,我们使用gfind解码,因为names和values都不能包含 '&' 和 '='我们可以用模式 '[^&=]+' 匹配他们: ~~~ cgi = {} function decode (s) for name, value in string.gmatch(s, "([^&=]+)=([^&=]+)") do name = unescape(name) value = unescape(value) cgi[name] = value end end ~~~ **URL编码** 这个函数将所有的特殊字符转换成 '%' 后跟字符对应的ASCII码转换成两位的16进制数字(不足两位,前面补0),然后将空白转换为 '+': ~~~ function escape(s) s = string.gsub(s, "([&=+%c])", function(c) return string.format("%%%02X", string.byte(c)) end) s = string.gsub(s, " ", "+") return s end function encode(t) local s = "" for k, v in pairs(t) do s = s .. "&" .. escape(k) .. "=" .. escape(v) end return string.sub(s, 2) -- remove first '&' end t = {name = "al", query = "a+b = c", q = "yes or no"} print(encode(t)) --> q=yes+or+no&query=a%2Bb+%3D+c&name=al ~~~ ### [](https://github.com/andycai/luaprimer/blob/master/04.md#5-stringgsub-全局字符串替换)(5) string.gsub 全局字符串替换 string.gsub 函数有三个参数:目标串,模式串,替换串,第四个参数是可选的,用来限制替换的数量。 ~~~ print(string.gsub("nck eats fish", "fish", "chips")) --> nick eats chips 1 ~~~ string.gsub 的第二个返回值表示他进行替换操作的次数: ~~~ print(string.gsub("fish eats fish", "fish", "chips")) --> chips eats chips 2 ~~~ 使用模式: ~~~ print(string.gsub("nick eats fish", "[AEIOUaeiou]", ".")) --> n.ck ..ts f.sh 4 ~~~ 使用捕获: ~~~ print(string.gsub("nick eats fish", "([AEIOUaeiou])", "(%1)")) --> n(i)ck (e)(a)ts f(i)sh 4 ~~~ 使用替换函数: ~~~ function f(s) print("found " .. s) end string.gsub("Nick is taking a walk today", "%a+", f) 输出: found Nick found is found taking found a found walk found today ~~~ ### [](https://github.com/andycai/luaprimer/blob/master/04.md#6-stringsub-stringbyte-stringformat)(6) string.sub, string.byte, string.format ~~~ s = "[in brackets]" print(string.sub(s, 2, -2)) --> in brackets ~~~ string.char 函数和 string.byte 函数用来将字符在字符和数字之间转换,string.char 获取0个或多个整数,将每一个数字转换成字符,然后返回一个所有这些字符连接起来的字符串。string.byte(s, i) 将字符串s的第i个字符的转换成整数。 ~~~ 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.format 和 C 语言的 printf 函数几乎一模一样,你完全可以照 C 语言的 printf 来使用这个函数,第一个参数为格式化串:由指示符和控制格式的字符组成。指示符后的控制格式的字符可以为:十进制'd';十六进制'x';八进制'o';浮点数'f';字符串's'。 ~~~ print(string.format("pi = %.4f", PI)) --> pi = 3.1416 d = 5; m = 11; y = 1990 print(string.format("%02d/%02d/%04d", d, m, y)) --> 05/11/1990 tag, title = "h1", "a title" print(string.format("<%s>%s", tag, title, tag)) -->

a title

~~~ ## [](https://github.com/andycai/luaprimer/blob/master/04.md#table)Table ~~~ table.concat table.insert table.maxn table.remove table.sort ~~~ ### [](https://github.com/andycai/luaprimer/blob/master/04.md#1-tablegetn)(1) table.getn ~~~ print(table.getn{10,2,4}) --> 3 print(table.getn{10,2,nil}) --> 2 print(table.getn{10,2,nil; n=3}) --> 3 print(table.getn{n=1000}) --> 1000 a = {} print(table.getn(a)) --> 0 table.setn(a, 10000) print(table.getn(a)) --> 10000 a = {n=10} print(table.getn(a)) --> 10 table.setn(a, 10000) print(table.getn(a)) --> 10000 ~~~ ### [](https://github.com/andycai/luaprimer/blob/master/04.md#2-tableinsert-tableremove)(2) table.insert, table.remove ~~~ table.isnert(table, value, position) table.remove(table, position) ~~~ table库提供了从一个list的任意位置插入和删除元素的函数。table.insert函数在array指定位置插入一个元素,并将后面所有其他的元素后移。 ~~~ a = {} for line in io.lines() do table.insert(a, line) end print(table.getn(a)) --> (number of lines read) ~~~ table.remove 函数删除数组中指定位置的元素,并返回这个元素,所有后面的元素前移,并且数组的大小改变。不带位置参数调用的时候,他删除array的最后一个元素。 ### [](https://github.com/andycai/luaprimer/blob/master/04.md#3-tablesort)(3) table.sort table.sort 有两个参数,存放元素的array和排序函数,排序函数有两个参数并且如果在array中排序后第一个参数在第二个参数前面,排序函数必须返回true。如果未提供排序函数,sort使用默认的小于操作符进行比较。 ~~~ lines = { luaH_set = 10, luaH_get = 24, luaH_present = 48, } function pairsByKeys (t, f) local a = {} for n in pairs(t) do table.insert(a, n) end table.sort(a, f) local i = 0 -- iterator variable local iter = function () -- iterator function i = i + 1 if a[i] == nil then return nil else return a[i], t[a[i]] end end return iter end for name, line in pairsByKeys(lines) do print(name, line) end ~~~ 打印结果: ~~~ luaH_get 24 luaH_present 48 luaH_set 10 ~~~ ## [](https://github.com/andycai/luaprimer/blob/master/04.md#coroutine)Coroutine ~~~ coroutine.create coroutine.resume coroutine.running coroutine.status coroutine.wrap coroutine.yield ~~~ ## [](https://github.com/andycai/luaprimer/blob/master/04.md#math)Math ~~~ math.abs math.acos math.asin math.atan math.atan2 math.ceil math.cos math.cosh math.deg math.exp math.floor math.fmod math.frexp math.huge math.ldexp math.log math.log10 math.max math.min math.modf math.pi math.pow math.rad math.random math.randomseed math.sin math.sinh math.sqrt math.tan math.tanh ~~~ ## [](https://github.com/andycai/luaprimer/blob/master/04.md#io)IO ~~~ io.close io.flush io.input io.lines io.open io.output io.popen io.read io.stderr io.stdin io.stdout io.tmpfile io.type io.write ~~~ ## [](https://github.com/andycai/luaprimer/blob/master/04.md#os)OS ~~~ os.clock os.date os.difftime os.execute os.exit os.getenv os.remove os.rename os.setlocale os.time os.tmpname ~~~ ## [](https://github.com/andycai/luaprimer/blob/master/04.md#file)File ~~~ file:close file:flush file:lines file:read file:seek file:setvbuf file:write ~~~ ## [](https://github.com/andycai/luaprimer/blob/master/04.md#debug)Debug ~~~ debug.debug debug.getfenv debug.gethook debug.getinfo debug.getlocal debug.getmetatable debug.getregistry debug.getupvalue debug.setfenv debug.sethook debug.setlocal debug.setmetatable debug.setupvalue debug.traceback ~~~
';