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%s>", tag, title, tag)) -->
';