模式匹配相關庫函數
按匹配查找:string.find (s,pattern [,init [,plain]])
兩個返回值,被捕獲內容的起始位置和終止位置,如未找到則返回nil。
參數s:指定字符串,參數pattern:匹配,可選參數init:初始查找位置(如果是負數將從字符串尾開始定位),可選參數plain:無參數時按匹配查找,當參數為true時使用單純字符串進行匹配。
按位置捕獲:string.sub (s,i [,j])
返回以i,j定位的子串內容。
參數s:指定字符串,參數i:初始查找位置(如果是負數將從字符串尾開始定位),可選參數j:無參數時等價j為最大值,如果j比整個字符串大則自動修正,如果j比i小則返回空字符串。
按匹配捕獲:string.match (s,pattern [,init])
返回按匹配捕獲的子串,如未捕獲則返回nil。如果在參數pattern中使用()進行捕獲則返回值變為捕獲到內容。
參數s:指定字符串,參數pattern:匹配,可選參數init:初始查找位置(如果是負數將從字符串尾開始定位)
按匹配捕獲並替換:string.gsub (s,pattern,replace [,n])
兩個返回值,成功替換后的新字符串和被替換的次數,如未找到匹配則返回s原始內容。
參數s:指定字符串,參數pattern:匹配,參數replace:替換內容(可以是表或函數),可選參數n:替換次數,無參數則全部替換。
迭代器函數:string.gmatch (s,pattern)
每次迭代返回一個匹配的子串內容,該函數用於逐一遍歷字符串中所有捕獲到的匹配。
參數s:指定字符串,參數pattern:匹配
模式匹配預置的字符分類
. -- 任意字符 %a -- 字母 %c -- 控制符,如\n %d -- 數字 %g -- 除空格外的可打印字符 %l -- 小寫字母 %p -- 標點符號 %s -- 空白字符 %u -- 大寫字母 %w -- 字母和數字 %x -- 十六進制數字 %n -- 第n次被()捕獲的內容,n是一個數字,如:%1 %2 %3,而%0則意味着整個匹配而不是捕獲 %f -- 前置排除模式 %b -- 范圍匹配,使用兩個字符參數確定前后成對的區域,如:%b<> %b{} %b33 %b-+ 遵循最遠距離貪婪匹配規則
魔法字符(修飾符)
% -- 轉義符 + -- 重復一次或多次 * -- 重復零次或多次(最遠距離貪婪匹配) - -- 重復零次或多次(最近距離匹配) ? -- 重復零次或一次(表示可有可無) ^ -- 錨定開頭 $ -- 錨定結尾 [] -- 自定義字符分類,分類間的關系是"或" () -- 捕獲,空的捕獲可以返回位置信息,如:字符串"Name",模式"()am()"返回2,4。
使用修飾符時一定要注意上下文,如:.*很可能匹配超預期
在結尾使用"-"並沒有意義,這樣只能匹配到空字符,-后面總是要跟上一些東西來限制擴展范圍
當模式匹配字母大寫時表示其補集,非字母代表其本身,在模式中%需要轉義,如%%。而匹配無意義的修飾符時也需要加轉義字符%。
前置排除模式:簡單來說%f[char-set]是判斷[char-set]后面緊跟的字符是否屬於[char-set]而[char-set]之前的字符不屬於[char-set],例如:"%f[%a]abc123"對於字符串"Hi+abc123"來說,字符a屬於[%a]而前面的+不屬於[%a]即模式成立。
()捕獲與%n配合可以對[]自定義字符分類中不確定的內容在后續進行進一步的確認。
例如:
s = [[then he said: "it's all right"!]] print (string.match (s, "(["'])(.-)%1") -->" it's all right 輸出了兩個參數,分別是"和it's all right。
以"或'開頭,零個或多個任意字符序列,遇到第一次捕獲到的匹配為結尾,使得不確定的字符分類在最后得到了確定的匹配
類似的例子如:長字符串或長注釋[==[ ]==]中不確定的=數量
翻譯一些例子
"[_%a][_%w]*" -- [下划線或任意字母]和[零個或多個下划線或任意字母或數字]*,匹配LUA中合法的標識符 "[+-]?%d+" -- [可有可無的正號或負號]?任意數字序列+,匹配123,-21,+456 "^%d" -- 任意數字開頭^,匹配整段字符串第一個字符是數字 "^[+-]?%d+$" -- 開頭^[可有可無正號或負號]?任意數字序列結尾$,匹配純整型數值
"%[(=*)%[(.-)%]%1%]" -- 轉義[捕獲1(零個或多個等號)轉義[捕獲2(零個或多個任意字符)轉義]捕獲1的內容%1轉義],匹配LUA長字符串樣式[==[]==]
替換
string.gsub的第三個參數不僅可以是字符串,還可以是函數或者表。
string.gsub配合%n替換
例如:
print (string.gsub ("Hello Lua", "(.)(.)", "%2%1")) --> eHll ouLa 4,將相鄰的兩個任意字符換位,共替換4次
當替換參數是函數時,會在每一次找到匹配時調用這個函數,並以捕獲的內容為參數,以這個函數返回值作為替換內容。
當替換參數是表時,會把第一個捕獲內容作為鍵,去查找表中的值作為替換內容,如果不成功,則當次不做任何替換。
例如:
tb={} tb.Hello="+" print (string.gsub ("Hello Lua", "%a+", tb)) --> + Lua 2, 以匹配到的字符序列為鍵去獲取表tb中對應該鍵的值,如果是標准字符串則使用這個字符串替換,如果沒找到鍵或者值不是字符串類型則不做改變。
本示例匹配到了2次但只替換1次。
小程序練習
-- 給定一個字符串,找出字符串中所有單詞並計算重復的次數,輸出前進行排序,優先輸出重復最多的單詞 do local txt = [[hi hi lua aaa b c c c cc]] -- 指定字符串 local tbl = {} for key in string.gmatch(txt, "%a+") do -- 每次迭代逐個捕獲表中單詞,存入表tbl tbl[key] = (tbl[key] or 0) + 1 -- 作為鍵存表,其值做一次計數自增 end local words = {} for k, v in pairs(tbl) do -- 把無序表tbl的鍵作為值按順序導入表words words[#words + 1] = k end table.sort (words, function(v1, v2) return tbl[v1] > tbl[v2] or tbl[v1] == tbl[v2] and v1 < v2 end) -- 排序表words,比較tbl中相關鍵的值(重復的次數),優先按次數最多排序,如果次數相等則按首字母順序排 for _,v in ipairs(words) do -- 遍歷數組輸出 print ("單詞 "..v.." 被找到 "..tbl[v].." 次") end end
--[[ 輸出結果
單詞 c 被找到 3 次
單詞 hi 被找到 2 次
單詞 aaa 被找到 1 次
單詞 b 被找到 1 次
單詞 cc 被找到 1 次
單詞 lua 被找到 1 次
--]]
學習輔助工具
