## 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)) --> <h1>a title</h1>
~~~
## [](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
~~~