Lua 學習筆記(下)

前面的部分見 Lua 學習筆記(上)javascript

4 輔助庫

輔助庫爲咱們用 Lua 與 C 的通訊提供了一些方便的函數。基礎 API 提供 Lua 與 C 交互的全部原始函數。輔助庫做爲更高層次的函數來解決一些通用的問題。html

輔助庫的全部函數定義在頭文件 luaxlib.h 中,函數帶有前綴 luaL_java

輔助庫函數是創建在基礎庫之上的,因此基礎庫作不了的事情輔助庫也作不了。git

有一些函數是用來檢查函數參數的,這些函數都有這樣的前綴 luaL_check 或者 luaL_opt。這些函數在檢查出問題後會拋出錯誤。因爲拋出的錯誤消息代表是參數錯誤(例如,「bad argument #1」),所以不要把這些函數用在參數之外的 Lua 值上。程序員

5 標準庫

標準 Lua 庫提供了許多有用的函數,這些函數都是直接用 C API 實現的。有一些函數提供了 Lua 語言自己所必要的服務(例如,typegetmetatable);有一些提供了通向「外部」的服務(例如,I/O);還有一些函數,能夠由 Lua 進行實現,可是因爲至關有用或者有重要的性能需求須要由 C 實現(例如 sort)。github

全部的庫都以 C 模塊的形式分開提供。5.1中,Lua有如下幾種標準庫:segmentfault

- 基礎庫
- 包庫
- 字符串操做庫
- 表操做庫
- 數學功能庫
- 輸入輸出庫
- 操做系統工具庫
- 調試工具庫

除了基礎庫和包庫,其餘庫都是做爲全局表的域或者對象的方法提供。閉包

[待補充]socket

5.1 基礎庫函數

基礎庫爲 Lua 提供了一些核心函數。若是沒有包含這個庫,那麼就可能須要本身來實現一些 Lua 語言特性了。ide

assert (v [, message])

若是其參數 v 的值爲假(nilfalse), 它就調用 error; 不然,返回全部的參數。 在錯誤狀況時, message 指那個錯誤對象; 若是不提供這個參數,參數默認爲 "assertion failed!" 。

例子

assert(5==4,"Number Not Equal!")    --> 報錯 Number Not Equal!
assert(nil)                         --> 報錯 assertion failed!

collectgarbage (opt [, arg])

控制垃圾回收器的參數有兩個,pause 和 step multipier。

參數 pause 控制了收集器在開始一個新的收集週期以前要等待多久。 隨着數字的增大就致使收集器工做工做的不那麼主動。 小於 1 的值意味着收集器在新的週期開始時再也不等待。 當值爲 2 的時候意味着在總使用內存數量達到原來的兩倍時再開啓新的週期。

參數 step multiplier 控制了收集器相對內存分配的速度。 更大的數字將致使收集器工做的更主動的同時,也使每步收集的尺寸增長。 小於 1 的值會使收集器工做的很是慢,可能致使收集器永遠都結束不了當前週期。 缺省值爲 2 ,這意味着收集器將之內存分配器的兩倍速運行。

該函數是垃圾回收器的通用接口,根據 opt 參數的不一樣實現不一樣的功能。

  • "stop": 中止垃圾回收。
  • "restart": 重啓垃圾回收。
  • "collect": 執行垃圾回收的完整循環。
  • "count": 返回 Lua 當前使用的總內存(單位爲 Kb)。
  • "step": 執行一步(一步可由多步組成)垃圾回收。步數可由參數 arg 控制(值越大,步數越多,0 表示執行一步(指最小的一步))。若是執行後完成了回收循環,返回 true
  • "setpause": 把 arg/100 做爲垃圾回收參數 pause 的新值。
  • "setstepmul": 把 arg/100 做爲垃圾回收參數 step mutiplier 的新值。

例子

進行垃圾回收先後的內存佔用狀況:

x = collectgarbage("count")
print(x)            --> 27.5615234375
collectgarbage("collect")
x = collectgarbage("count")
print(x)            --> 26.7490234375

dofile (filename)

打開該名字的文件,並執行文件中的 Lua 代碼塊。 不帶參數調用時, dofile 執行標準輸入的內容(stdin)。 返回該代碼塊的全部返回值。 對於有錯誤的狀況,dofile 將錯誤反饋給調用者 (即,dofile 沒有運行在保護模式下)。

例子

同一目錄下新建兩個 Lua 文件,代碼及輸出:

-- another.lua
return "Message from another file!"

-- sample.lua
x = dofile("./another.lua")
print(x)    --> Message from another file!

dofile 在這裏等價於

function dofile()
    function func()
        return "Message from another file!"
    end

    return func()
end

因而等價的輸出爲

print(dofile()) --> Message from another file!

error (message [, level])

終止所保護的函數,拋出 message 消息,再也不返回。

一般這個函數會在拋出的消息前面加上發生錯誤的地址信息。堆棧等級決定添加哪一個地址。若是堆棧等級爲 0 ,不返回地址信息;若是爲 1,返回 error 語句所在位置;若是爲 2,返回調用 error所在函數的位置;依此類推。

定義

error([報錯消息],[堆棧等級]=1)

例子

function division(a,b)
    if b == 0 then error("Divisor cannot be 0!",2) end      -- level 值爲 1 時,錯誤信息指向這裏
    return a / b
end

print(division(5,1))
print(division(5,0))        -- level 值爲 2 時,錯誤信息指向這裏

_G

_G 持有全局環境的變量,Lua 自己用不到這個變量,更改變量不會影響到全局環境;反過來也同樣。

getfenv (f)

返回函數的環境。 f 能夠是一個 Lua 函數,也能夠是函數在堆棧中的等級。等級 1 表明調用 getfenv() 的那個函數。若是傳入的函數不是 Lua 函數,或者 f 是 0,那麼 getfenv 返回 全局環境。

~~[待補充]不是太明白,沒能給出合適的代碼~~
參考 Lua中的環境概念

定義

getfenv([目標函數]=1)

例子

獲取全局環境:

for k,v in pairs(_G) do
print(k,v)
end

--string            table: 0x7ff200f02330
--xpcall            function: 0x7ff200d03cc0
--package           table: 0x7ff200e00000
--tostring          function: 0x7ff200d04560
--print             function: 0x7ff200d046a0
--os                table: 0x7ff200f01cb0
--unpack            function: 0x7ff200d04610
--require           function: 0x7ff200f006f0
--getfenv           function: 0x7ff200d042f0
--setmetatable      function: 0x7ff200d044a0
--next              function: 0x7ff200d04260
--assert            function: 0x7ff200d03fc0
--tonumber          function: 0x7ff200d04500
--io                table: 0x7ff200f014a0
--rawequal          function: 0x7ff200d046f0
--collectgarbage    function: 0x7ff200d04010
--arg               table: 0x7ff200e01360
--getmetatable      function: 0x7ff200d04340
--module            function: 0x7ff200f006a0
--rawset            function: 0x7ff200d047a0
--math              table: 0x7ff200e00040
--debug             table: 0x7ff200e00a00
--pcall             function: 0x7ff200d042b0
--table             table: 0x7ff200f00790
--newproxy          function: 0x7ff200d04820
--type              function: 0x7ff200d045c0
--coroutine         table: 0x7ff200d048c0
--_G                table: 0x7ff200d02fc0
--select            function: 0x7ff200d04400
--gcinfo            function: 0x7ff200d03000
--pairs             function: 0x7ff200d03e00
--rawget            function: 0x7ff200d04750
--loadstring        function: 0x7ff200d04200
--ipairs            function: 0x7ff200d03d70
--_VERSION          Lua 5.1
--dofile            function: 0x7ff200d04110
--setfenv           function: 0x7ff200d04450
--load              function: 0x7ff200d041b0
--error             function: 0x7ff200d04160
--loadfile          function: 0x7ff200d043a0

getmetatable (object)

若是對象沒有元表,返回空;若是對象有 __metatable 域,返回對應的值;不然,返回對象的元表。

例子

對象有 __metatable 域的狀況:

t = {num = "a table"}

mt = {__index = {x = 1,y = 2},__metatable = {__index = {x = 5,y = 6}}}
setmetatable(t, mt)

print(getmetatable(t).__index.x)  --> 5
print(t.x)                        --> 1

~~進行操做時的元表依舊是與值直接關聯的那個元表,不知道這樣子處理有什麼做用?~~

ipairs (t)

返回三個值:迭代器、傳入的表 t、值 0 。迭代器可以根據傳入的表 t 和索引 i 獲得 i+1 和 t[i+1] 的值。

其實現形式相似於這樣:

function ipairs(t)

    function iterator(t,i)
        i = i + 1
        i = t[i] and i      -- 若是 t[i] == nil 則 i = nil;不然 i = i
        return i,t[i]
    end

    return iterator,t,0

end

例子

使用 ipairs 對錶進行遍歷,會從鍵值爲 1 開始依次向後遍歷,直到值爲 nil。

t = {"1","2",nil,[4]="4"}
-- t = {"1","2",[4]="4"}   -- 使用該表會獲得相同的輸出

for i,v in ipairs(t) do
    print(i,v)
end

--> 1   1
--> 2   2

load (func [, chunkname])

經過傳入函數 func 的返回值獲取代碼塊片斷。func 函數的後一次調用返回的字符串應當能與前一次調用返回的字符串銜接在一塊兒,最終獲得完整的代碼塊。函數返回 nil 或無返回值時表示代碼塊結束。

load 函數會將獲得的代碼塊做爲函數返回。返回函數的環境爲全局環境。若是出現錯誤,load 會返回 nil 和 錯誤信息。

chunkname 做爲該代碼塊的名稱,用在錯誤信息與調試信息中。

例子

[待補充]

loadfile ([filename])

使用方式與 dofile 相似,函數內容與 load 相似。從文件中獲取代碼塊,若是沒有指定文件,則從標準輸入中獲取。

loadfile 把文件代碼編譯爲中間碼,以文件代碼做爲一個代碼塊(chunk),並返回包含此代碼塊的函數。
編譯代碼成中間碼,並返回編譯後的chunk做爲一個函數。 若是出現錯誤,則返回 nil 以及錯誤信息。

使用 loadfile,能夠一次編譯屢次運行;而每次使用 dofile,都會執行一次編譯。

例子

同一目錄下新建兩個 Lua 文件,代碼及輸出:

-- sample.lua
f = loadfile("./sample.lua")
print(f())
--> Message from another file!
--> 0

-- another.lua
function fun()
 print("Message from another file!")
 return 0
end
res = fun()
return res

loadfile 在這裏等價於

function loadfile()
    function fun()
     print("Message from another file!")
     return 0
    end
    res = fun()
    return res
end

loadstring (string [, chunkname])

與 load 相似,只不過是從字符串中獲取代碼塊。

要想加載並運行所給的字符串,使用以下慣用形式:

assert(loadingstring(s))()

next (table [, index])

返回傳入的表中下一個鍵值對。

定義

next([表],[鍵]=nil)

第一個參數是要操做的表,第二個參數是表中的某個鍵。若是傳入的鍵值爲 nil ,則函數返回第一個鍵值對。若是傳入一個有效的鍵值,則輸出下一對鍵值對。若是沒有下一個鍵值對,返回 nil。

根據定義,可使用 next 來判斷一個表是否爲空表。

注意:

鍵值對的遍歷順序是不必定的,即便是對數字索引也是如此。若是想要按照數字索引的順序獲取鍵值對,參見 ipairs (t) 函數。

例子

t = {"table",["a"] = 5, ["c"] = 6}

-- index 爲 nil
print(next(t, nil))         --> 1   table

-- index 爲 無效鍵
print(next(t,"d"))          --> 編譯錯誤

-- index 爲 數字索引
print(next(t,1))            --> a   5

-- index 爲 通常鍵
print(next(t, "a"))         --> c   6

-- index 爲 最後一個鍵
print(next(t,"c"))          --> nil

遍歷順序與定義順序不一致的例子:

t = {[1]="table",b = 4,["a"] = 5, ["c"] = 6, func}

t.func = function (...)
    return true
end

for k,v in pairs(t) do
    print(k,v)
end
--> a   5
--> func    function: 0x7f7f63c0ad50
--> c   6
--> b   4

並且從上面的例子中能夠看出 name = exp 的鍵值對形式會佔用

pairs (t)

返回三個值:next 函數,表 t,nil。一般用來遍歷表中的全部鍵值對。
若是 t 有元方法 __pairs ,將 t 做爲參數 傳入該函數並返回前三個返回值。

在使用 pairs 函數遍歷表的過程當中,能夠刪除域或者修改已有的域,可是若是添加新的域,可能出現沒法預期的問題。

例子

t = {"table",["a"] = 5, ["c"] = 6}
for k,v in pairs(t) do
    print(k,v)
end
--> 1   table
--> a   5
--> c   6

在遍歷表的過程當中添加新的域致使問題出現的狀況:

t = {"table",["a"] = 5, ["c"] = 6}

for k,v in pairs(t) do
    -- 添加一個新的域
    if k == 'a' then
        t[2] = 8
    end
    print(k,v)
end
--> 1   table
--> a   5

pcall (f [, arg1, ...])

以保護模式調用傳入的函數,也就是說不會拋出錯誤。若是捕獲到拋出的錯誤,第一個參數返回 false,第二個參數返回錯誤信息;若是沒有出現錯誤,第一個參數返回 ture,後面的參數返回傳入函數的返回值。

#

function fun(a,b)

    assert(not(b == 0), "divisor can't be 0 !")

    return a / b    
end

success, res = pcall(fun,5,0) --> false .../sample.lua:3: divisor can't be 0 !
success, res = pcall(fun,5,1) --> true  5

print (...)

僅做爲快速查看某個值的工具,不用作格式化輸出。正式的格式化輸出見 string.format 與 io.write。

rawequal (v1, v2)

raw 做爲前綴的函數均表示該方法在不觸發任何元方法的狀況下調用。

rawequal 檢查 v1 是否與 v2 相等,返回比較結果。

例子

t = {"value"}
s = "value"
s2 = "value"
print(rawequal(t, s))     --> false
print(rawequal(s, s2))    --> true

rawget (table, index)

獲取 table 中鍵 index 的關聯值,table 參數必須是一個表,找不到返回 nil 。

例子

t = {"value",x = 5}

print(rawget(t, 1))     --> value
print(rawget(t, "x"))   --> 5
print(rawget(t, 2))     --> nil
print(rawget("value",1))--> bad argument #1 to 'rawget' (table expected, got string)

rawset (table, index, value)

將 table[index] 的值設置爲 value 。table 必須是一張表,index 不能是 nil 或 NaN 。value 能夠是任何值。返回修改後的 table 。

例子

t = {"value",x = 5}
t2 = {"sub table"}
rawset(t, 1,"new value")
rawset(t, "y", 6)
rawset(t, t2,"sub table")
rawset(t,NaN,"NaN")         --> table index is nil

print(t[1])                 --> new value
print(t.y)                  --> 6
print(t[t2])                --> sub table

select (index, ...)

index 能夠是數字或者字符 '#' 。當 index 爲數字時,返回第 index + 1 個參數及後面的參數(支持負數形式的 index);當 index 爲 '#' 時,返回參數的個數(不包括第一個參數)。

例子

t = {"table",x = 5}
t2 = {"table2"}

print(select(  1, 1, t, t2))    --> 1  table: 0x7fad7bc0a830 table: 0x7fad7bc0ac20
print(select( -3, 1, t, t2))    --> 1  table: 0x7fad7bc0a830 table: 0x7fad7bc0ac20
print(select("#", 1, t, t2))    --> 3

setfenv (f, table)

設置函數 f 的環境表爲 table 。f 能夠是一個函數,或者是表明棧層級的數字。棧層級爲 1 的函數是那個調用 setfenv 的函數,棧層級爲 2 的函數就是更上一層的函數。 setfenv 返回 f。

特別的,若是 f 爲 0,那麼 setfenv 會把全局環境設置爲 table 。而且不作任何返回。

Lua 的以後版本中去掉了 setfenv 和 getfenv 函數。

例子

使用棧層級操做 setfenv 的例子:

function foobar(...)

    -- 設置 foobar 的環境
    t = {}
    setmetatable(t, {__index = _G })
    setfenv(1,t)
    a = 1
    b = 2

    -- 輸出 foobar 的環境
    for k,v in pairs(getfenv(1)) do
        print(k,v)
    end
    print()

    function foo(...)
        -- 設置 foo 的環境,繼承 foobar 的環境
        local t = {}
        setmetatable(t, {__index = _G})
        setfenv(1,t)
        x = 3
        y = 4

        -- 輸出 foo 的環境
        for k,v in pairs(getfenv(1)) do
            print(k,v)
        end
        print()

        -- 再次設置 foobar 的環境
        setfenv(2, t)
    end


    foo()

    -- 再次輸出 foobar 的環境
    for k,v in pairs(getfenv(1)) do
        print(k,v)
    end
end

foobar()

--> a   1
--> b   2
--> 
--> y   4
--> x   3
--> 
--> y   4
--> x   3

將 setfenv 用於模塊加載:

-- sample.lua 文件
local FuncEnv={}    -- 做爲環境
setmetatable(FuncEnv, {__index = _G}) -- 爲了可以訪問本來全局環境的值,將全局環境表(_G)放在元表中

local func=loadfile("other.lua")    -- 返回一個函數,函數以 other 文件內容做爲代碼塊
setfenv(func,FuncEnv)
func()                              -- 執行代碼塊,獲得定義的 message 函數,該函數會存在環境中
FuncEnv.message()                   --經過環境調用函數,FuncEnv 此時就至關於一個獨立模塊
-- other.lua 文件
function message()
    print("Message from another file!")
end

本小節參考了 斯芬克斯設置函數環境——setfenvicydaylua5.1中的setfenv使用 兩篇博客。

setmetatable (table, metatable)

給 table 關聯元表 metatable 。返回參數 table 。

若是元表定義了 __metatable 域,會拋出錯誤。

metatable 參數爲 nil 表示解除已經關聯的元表。

例子

-- 關聯一個定義了加法操做的元表
t = setmetatable({}, {__add = function(a,b)
    if type(a) == "table" and type(b) == "table" then
        return a.num + b.num
    end
end})

t.num = 5
t2 = {num = 6}
print(t+t2)         --> 11      -- 只要有一個表進行了關聯就可以進行運算

setmetatable(t, nil)            

-- 解除關聯後再進行加法運算會報錯
print(t+t2)         --> attempt to perform arithmetic on global 't' (a table value)

tonumber (e [, base])

tonumber([值],[基數]=10)

嘗試把 e 轉換爲十進制數值並返回。若是沒法轉換返回 nil 。

base 表示傳入參數的進制,默認爲 10 進制。base 的可輸入範圍 [2,36]。高於 10 的數字用字母表示,A-Z 分別表示 11-35 。

例子

print(tonumber(123))            --> 123
print(tonumber("123"))          --> 123
print(tonumber("abc"))          --> nil
print(tonumber("abc", 20))      --> 4232
print(tonumber("ABC", 20))      --> 4232

tostring (e)

能將任意類型的值轉換爲合適的字符串形式返回。要控制數字轉換爲字符串的方式,使用 string.format(formatstring,...)

若是值所關聯的元表有 __tostring 域,則使用該域的元方法獲取字符串。

例子

function func()
    print("this is a function")
end
t = {name = "table"}

print(tostring(123))        --> 123
print(tostring("abc"))      --> abc
print(tostring(func))       --> function: 0x7f86348013b0
print(tostring(t))          --> table: 0x7f86348013e0

type (v)

返回 v 的類型,類型以字符串形式返回。 有如下八種返回值: "nil" , "number", "string", "boolean", "table", "function", "thread", "userdata"。

例子

type(nil)                   --> "nil"
type(false)                 --> "boolean"
type(123)                   --> "number"
type("abc")                 --> "string"

print(type(nil) == "nil")   --> true

unpack (list [, i [, j]])

unpack([列表],[起始位置]=1,[返回個數]=[列表長度])

返回表中的各個域的值,等價於返回

return list[i], list[i+1], ···, list[j]

例子

t = {1,2,3,a = 4,b = 5}

print(unpack(t, 1, 4))      --> 1   2   3   nil

_VERSION

包含有當前解釋器版本號的全局變量,當前版本的值爲 "Lua 5.1"。

xpcall (f, err [, arg1, ...]

pcall (f, arg1, ...) 相似。不一樣的是,若是 f 函數拋出了錯誤,那麼 xpcall 不會返回從 f 拋出的錯誤信息,而是使用 err 函數返回的錯誤信息。

例子

function fun(a,b)   -- 這裏的參數沒什麼實際做用,就是展現下用法
    error("something wrong !!", 1)
end

-- pcall 
local success, res = pcall(fun,1,2)
print(success,res)      --> false   .../sample.lua:2: something wrong !!

-- xpcall
local success, res = xpcall(fun,function()
    return "an error occured !!"
end,1,2)
print(success,res)      --> false   an error occured !!

5.4 字符串操做

5.4.1 模式

字符類

字符類表明一組字符。能夠用下列組合來表示一個字符類。

組合 表明字母 表明字符類型
x (變量 x) ^$()%.[]*+-?之外的任一字符
. (dot) 任意字符
%a (alphabet) 字母
%b (bracket) 對稱字符以及字符間的內容
%c (control) 控制字符(即各種轉義符)
%d (digits) 數字
%l (lowercase) 小寫字母
%p (punctuation) 標點符號
%s (space) 空格
%u (uppercase) 大寫字母
%w (word) 字母和數字
%x (hexadecimal) 十六進制字符
%z (zero) 值爲 0 的字符,即 '\0'
%x (變量 x) 字母和數字之外的任一字符

若是組合中的字符寫成大寫形式(例如將 '%a' 寫成 '%A'),至關於對原來所表明的字符類型取補集

例子:

前兩行的數字標出每一個字符的下標。find函數返回找出第一個符合查找條件的字符的下標。

-----------------00000000001111111112 222222222333333333344444444445555 5
-----------------12345678901234567890 123456789012345678901234567890123 4
x = string.find("Tutu is a young man.\n His student number is 20230001.\0","i")
    --> 6
x = string.find("Tutu is a young man.\n His student number is 20230001.\0",".")
    --> 1
x = string.find("Tutu is a young man.\n His student number is 20230001.\0","%a")    --> 1   
x = string.find("Tutu is a young man.\n His student number is 20230001.\0","%c")    --> 21 
x = string.find("Tutu is a young man.\n His student number is 20230001.\0","%d")    --> 45 
x = string.find("Tutu is a young man.\n His student number is 20230001.\0","%l")    --> 2   
x = string.find("Tutu is a young man.\n His student number is 20230001.\0","%p")    --> 20 
x = string.find("Tutu is a young man.\n His student number is 20230001.\0","%s")    --> 5   
x = string.find("Tutu is a young man.\n His student number is 20230001.\0","%u")    --> 1   
x = string.find("Tutu is a young man.\n His student number is 20230001.\0","%w")    --> 1   
x = string.find("Tutu is a young man.\n His student number is 20230001.\0","%x")    --> 9   
x = string.find("Tutu is a young man.\n His student number is 20230001.\0","%z")    --> 54

() 表示捕捉,find的第三個參數返回被捕捉到的字符串,在這裏即返回找到的那個字符。

x,y,z = string.find("%()~!@#$%^&*():\";\'?<>._[]","(%%)")   --> 1   1   %
x,y,z = string.find("%()~!@#$%^&*():\";\'?<>._[]","(%#)")   --> 7   7   #
x,y,z = string.find("%()~!@#$%^&*():\";\'?<>._[]","(%\")")  --> 16  16  "

下句中的 + 表示取一個或多個知足條件的連續字符。

--1 2 3 4 5 6 7 8
x,y = string.find("\a\b\f\n\r\t\v\0","%c+")     --> 1   7

上句基本列出了全部控制字符,並非全部轉義符都是控制字符,例如 \\\xff 不屬於控制字符。

match 函數返回符合匹配條件的字符子串。

x = string.match("0123456789ABCDEFabcdefg","%x+")   --> 0123456789ABCDEFabcdef

輸出的符號即爲 %x 所支持的全部字符。

%b 的使用方法與前面的組合形式略有不一樣,其形式爲 %bxy,使用示例以下:

---------------------00000000001111111112 22222222233333333334444444444555555 5
---------------------12345678901234567890 12345678901234567890123456789012345 6
x,y,z = string.find("Tutu is a young man.\n His student number is [20230001].\0","(%b[])")  --> 45  54  [20230001]
x,y,z = string.find("Tutu is a young man.\n His student number is _20230001_.\0","(%b__)")  --> 45  54  _20230001_
x,y,z = string.find("Tutu is a young man.\n His student number is _20230001_.\0","(%b21)")  --> 48  53  230001

[] 字符集

字符集操做是對字符類組合的一個擴展。能夠經過 [] 制定出用戶所需的一套字符選取範圍。

---------------------0000000001111111111222222222
---------------------1234567890123456789012345678
x,y,z = string.find("[Email]: tangyikejun@163.com","([123])")           --> 22  22  1
x,y,z = string.find("[Email]: tangyikejun@163.com","([l]])")            --> 6   7   l]
x,y,z = string.find("[Email]: tangyikejun@163.com","([1-3])")           --> 22  22  1
x,y,z = string.find("[Email]: tangyikejun@163.com","([^1-3])")          --> 1   1   [
x,y,z = string.find("[Email]: tangyikejun@163.com","([^%d])")           --> 1   1   [
x,y,z = string.find("[Email]: tangyikejun@163.com","([0-9][%d][%d])")   --> 22  24  163
x,y,z = string.find("[Email]: tangyikejun@163.com","([0-9]+)")          --> 22  24  163

使用特色:

  1. 每一個字符集僅限定一個字符的範圍。
  2. 連字符 - 用於限定字符的範圍,值域根據字符在ASCII碼中對應的值得出,例如 [0-7] 表明字符範圍爲 0-7。
    x,y,z = string.find("!\"#$%&0123","([$-1]+)") --> 4 8 $%&01
  3. 添加 ^ 表示對指定的字符範圍取補集。[^%d] 等價於 [%D]

模式項

模式項 做用
+ 匹配1個或多個字符,儘量多地匹配
- 匹配0個或多個字符,儘量少地匹配
* 匹配0個或多個字符,儘量多地匹配
匹配0個或1個字符,儘量多地匹配

使用特色:

  1. 模式項都是針對前一個字符而言的。例如 abc- 做用於字符 c
---------------------0000000001
---------------------1234567890
x,y,z = string.find("aaaabbbccc","(%a+)")       --> 1   10  aaaabbbccc
x,y,z = string.find("bbbccc","(a+)")            --> nil nil nil
x,y,z = string.find("aaaabbbccc","(ab-c)")      --> 4   8   abbbc
-- x,y,z = string.find("aaaaccc","(ab-c)")      --> 4   5   ac
-- x,y,z = string.find("aaaaccc","(ab*c)")      --> 4   5   ac
-- x,y,z = string.find("aaaabccc","(ab?c)")     --> 4   6   abc
-- x,y,z = string.find("aaaabccc","(ba?c)")     --> 5   6   bc
---------------------000000000111 111111122
---------------------123456789012 345678901
x,y,z = string.find("tangyikejun\0 163.com","(%z%s%w+)")    --> 12  16  
x,y,z = string.find("tangyikejun\0163.com","(%z%d%w+)")     --> nil nil     nil

注意: \0 後面不能跟數字。並且用 find 返回的匹配字符串沒法輸出 \0 以後的部分。

模式

多個模式項組合造成模式

  • 模式的前面添加 ^ 表示匹配從目標字符串的起始位置開始。
  • 模式的末尾添加 $ 表示匹配目標字符串的末尾子串。
  • 其餘位置的 ^$ 做爲普通字符處理。
---------------------0000000001111111111222222222
---------------------1234567890123456789012345678
x,y,z = string.find("[Email]: tangyikejun@163.com","^(.%a+)")   -->1    6   [Email
x,y,z = string.find("[Email]: tangyikejun@163.com","(%a+)$")    -->26   28  com

()捕捉

捕捉是指將括號內的組合匹配結果保存起來,每一個括號保存一個結果。
保存的數據的順序按照左括號的順序排列。

x,y,z,h,l = string.find("Tutu is a young man.\n His student number is _20230001_.\0","((%a+%s)(%a+%s)%b__)")    --> 35  54  number is _20230001_    number  is

字符串模式匹配可參考Lua模式匹配

5.4.2 庫函數

  • 字符串的下標從1開始。正數下標表示正向下標,負數表示反向下標(例如 -1 表示字符串最後一個字符)。
  • 函數均默認支持模式匹配。
  • 返回的匹配字符串沒法輸出 \0 以後的部分。

string.find(s,pattern[,init[,plain]])

查找字符串的子串,若是找到,返回子串的起始位置、結束位置;找不到返回 nil。
若是使用捕獲(即對模式串用括號包裹起來),則一併返回匹配獲得的字符串。

定義

string.find([字符串],[待查找字符串],[查找起始位置]=1,[禁用模式匹配]=false)

只有顯式指定了 init 參數才能控制 plain 參數。

例子

x,y,z = string.find("1001 is a Robot", "Robot")
print(x,y,z)                                --> 11 15   nil
x,y,z = string.find("1001 is a Robot","1%d",1,true)
print(x,y,z)                                --> nil nil nil
x,y,z = string.find("1001 is a Robot","(%d+)",1,false)
print(x,y,z)                                --> 1   2   1001

string.match(s,pattern[,init])

string.find 相似,返回值不同。string.match 查找字符串的子串,若是找到,返回子串;找不到返回 nil。

支持模式匹配。

定義

例子

x = string.match("1001 is a Robot","001")
print(x)                --> 001                             
x = string.match("1001 is a Robot","%d%d")
print(x)                --> 10

string.gmatch(s,pattern)

返回一個迭代函數,該函數每執行一次,就返回下一個捕捉到的匹配(若是沒有使用捕捉,就返回整個匹配結果)。

例子

for s in string.gmatch("I have a Dream.","%a+") do
    print(s)
end
--> I
--> have
--> a
--> Dream
t = {}
s = "name=tangyikejun, number=20250001"

-- 將捕獲的兩個子串分別做爲鍵和值放到表t中
for k, v in string.gmatch(s, "(%w+)=(%w+)") do
    t[k] = v
end

-- 輸出表t
for k,v in pairs(t) do
    print(k,v)
end

--> name    tangyikejun
--> number  20250001

string.format(formatstring,...)

返回格式化以後的字符串。

定義

例子

string.format("My name is %s", "tangyikejun")   --> My name is tangyikejun

string.len(s)

返回字符串長度

string.lower(s)

返回小寫字母的字符串

string.upper(s)

返回大寫字母的字符串

string.rep(s,n)

對字符串進行重複

定義

string.rep([字符串],[重複次數])

例子

string.rep("Hello",4)   -- HelloHelloHelloHello

string.reverse(s)

返回反轉後的字符串。

string.sub(s,i[,j])

返回子字符串。

定義

string.sub([字符串],[開始字符下標],[結束字符下標]=-1)

例子

x = string.sub("tangyikejun",7)
print(x)                --> kejun
x = string.sub("tangyikejun",1,-6)
print(x)                --> tangyi

string.gsub(s,pattern,repl[,n])

根據模式匹配對字符串中每個匹配部分都作替換處理,返回替換後的字符串。

定義

string.gsub([字符串],[模式匹配],[替換字符],[最大替換次數] = 無限制)

repl 參數([替換字符])支持 字符串、表、函數。

若是 repl 是字符串,那麼該字符串就是用於替換的字符串。同時支持 %n 轉義符操做,n 的範圍是 0-9。n 範圍爲 [1,9] 時表示第 n 個捕獲的匹配字符串,%0 表示整個匹配的字符串,%% 表示替換爲一個 %

若是 repl 是表,那麼將捕獲的第一個字符串做爲鍵值(Key)進行查詢(沒有定義捕捉則以整個匹配的字符串爲鍵值),查到的值做爲替換的字符串。

若是 repl 是函數,那麼每次匹配成功都會調用該函數,並以按序以全部捕捉做爲參數傳入函數。沒有捕捉則以整個匹配的字符做爲參數。

若是從表或函數獲得是字符串或者是數字,就將其用於替換;若是獲得的是 false 或 nil,那麼匹配部分將不會發生變化。

例子

repl 爲字符串

s = "Never say die."
x = string.gsub(s,"die","never")            --> Never say never.
x = string.gsub(s,"die","'%0'")             --> Never say 'die'.
x = string.gsub(s,"(%a+)%s%a+%s(%a+)","%2") --> die.

限制最大替換次數

s = "never say never."
x = string.gsub(s,"never","Never",1)    --> Never say never.

repl 是表

t = {name="Lua",version="5.1"}
x = string.gsub("$name-$version.tar.gz","$(%a+)",t) --> Lua-5.1.tar.gz

repl是函數

x = string.gsub("4+5 = $return 4+5$","%$(.-)%$",function(s)return loadstring(s)() end)  --> 4+5 = 9
x = string.gsub("23+45=$result", "((%d+)%+(%d+)=)%$%a+", function (s,a,b)
    sum = a+b
    return s..sum
end)    --> 23+45=68

~~注意:彷佛只支持匿名函數。~~

從表或函數返回的是 false 或 nil

x = string.gsub("4+5 = $return 4+5$","%$(.-)%$",function(s)return nil end)  --> 4+5 = $return 4+5$
t = {name="Lua",version=false}
x = string.gsub("$name-$version.tar.gz","$(%a+)",t) --> Lua-$version.tar.gz

string.byte(s[,i[,j]])

返回字符的 ASCII 碼值。

定義

string.byte([字符串],[起始下標]=1,[結束下標]=[起始下標])

例子

x,y,z = string.byte("abc",2)    --> 98  nil nil
x,y,z = string.byte("abc",1,3)  --> 97  98  99

string.char(...)

根據傳入的 ASCII 編碼值([0-255])獲得對應的字符,傳入多少編碼值就返回多長的字符串。

例子

x = string.char(98,99,100)  --> bcd

若是輸入字符超限會編譯報錯。

string.dump(function)

返回函數的二進制表示(字符串形式),把這個返回值傳給 loadingstring 能夠得到函數的一份拷貝(傳入的函數必須是沒有上值的 Lua 函數)。

例子

function sum(a,b)
    return a + b
end

s = string.dump(sum)
x = loadstring(s)(4,4) -- 8

參考連接

BNF範式簡介 (簡要介紹 BNF)
Lua入門系列-果凍想(對Lua進行了較爲全面的介紹)
Lua快速入門(介紹 Lua 中最爲重要的幾個概念,爲 C/C++ 程序員準備)
Lua 5.1 中文手冊(全面的 Lua5.1 中文手冊)
Lua 5.3 中文手冊(雲風花了6天寫的,天哪,我看都要看6天的節奏呀)
Lua迭代器和泛型for(介紹 Lua 迭代器的詳細原理以及使用)
How do JavaScript closures work?——StackOverflow(詳細介紹了 Javascript 中閉包的概念)
Lua模式匹配(參考了此文中對 %b 的使用)
LuaSocket(LuaSocket 官方手冊)
Lua loadfile的用法, 與其餘函數的比較(loadfile的介紹部分引用了此文)
Lua 的元表(對元表的描述比較有條理,通俗易懂,本文元表部分參考了此文)
設置函數環境——setfenv(解釋瞭如何方便地設置函數的環境,以及爲何要那樣設置)
lua5.1中的setfenv使用(介紹了該環境的設置在實際中的一個應用)

相關文章
相關標籤/搜索