## 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
~~~