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