Lua的字符串匹配與正則表達式


Lua的字符串匹配與正則表達式

使用lua一段時間了,簡單總結下string庫中的幾個與正則相關的函數。這些函數是find,match, gmatch和gsub。然后是lua中支持的正則。文中的例子在lua5.3的命令行中試驗過。5.1版的需要在提示符前加一個=號或加return空格。

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

  1. 在字符串s中匹配pattern,如果匹配成功返回第一個匹配到的子串的起始索引和結束索引,如果pattern中有分組,分組匹配的內容也會接着兩個索引值之后返回。如果匹配失敗返回nil。
  2. 可選數值參數init表示從s中的哪個索引位置開始匹配,缺省值是1,可以為負索引。
  3. 可選布爾值參數plain為true時,pattern作為普通字符串匹配,所有正則中的元字符都只被作為普通字符解析。(這個參數並不是匹配字符串的結束索引)
    #########

    string.find('Hanazawa Kana', 'na')
    3 4
    string.find('Hanazawa Kana', '[%a]+')
    1 8
    string.find('2015-5-12 13:53', '(%d+)-(%d+)-(%d+)')
    1 9 2015 5 12
    string.find('2015-5-12 13:53', '(%d+)-(%d+)-(%d+)', 1, true)
    nil
    string.find('%a1234567890%a', '%a', 3, true)
    13 14

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

在字符串s中匹配pattern,如果匹配失敗返回nil。否則,當pattern中沒有分組時,返回第一個匹配到的子串;當pattern中有分組時,返回第一個匹配到子串的分組,多個分組就返回多個。可選參數init表示匹配字符串的起始索引,缺省為1,可以為負索引。

> string.match('2015-5-12 13:53', '%d+-%d+-%d+')
2015-5-12
> string.match('2015-5-12 13:53', '(%d+)-(%d+)-(%d+)')
2015	5	12
> string.match('2015-5-12 13:53', '((%d+)-(%d+)-(%d+))')
2015-5-12	2015	5	12

可以發現,所有用到match的地方都可以用find來實現。match是find的一個簡化版

string.gmatch(s, pattern)

返回一個迭代器。每當迭代器調用時,返回下一個匹配到的子串,如果pattern中有分組,返回的是子串對應的分組。gmatch也可以用find和循環來實現。

> for s in string.gmatch('2015-5-12 22:20', '%d+') do print(s) end
2015
5
12
22
20
> for s in string.gmatch('Hanazawa Kana', 'a(%a)a') do print(s) end --找出形如“a字母a”中間的字母
n
w
n
> for k, v in string.gmatch('a=214,b=233', '(%w+)=(%w+)') do print(k, v) end
a	214
b	233

看上面第二個測試例子,處於兩個a字母中間的單個字母還有‘z’,但循環並沒有輸出。原因是在'ana'匹配成功之后,接下來匹配是從'z'開始的,z沒有被匹配到。正確的模式pattern應該不要捕獲'a(%a)a'的后面的a,用python的正則可以寫成'a(\w)(?=a)',他不會消耗掉后面的a。但是lua不支持(?=...)。(python中\w表示單詞字符[a-zA-Z0-9_],記不清就把這類元字符列出來 如 %a寫成[a-zA-Z] 。)

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

替換字符串函數!這個功能應該是字符串處理中實用性最強的一個。
把字符串中用模式pattern匹配到的所有子串替換為repl指代的子串,返回替換后的字符串和替換的次數。可選數值參數n表示最多可替換的次數。
參數repl可以是正則表達式,也可以是函數。當repl是函數時,函數的參數是模式pattern捕獲的子串,和match類似,有分組返回分組,無分組返回整個子串。函數最后應該返回一個字符串。如果repl是正則表達式,可以用分組序號引用匹配到的分組。

> string.gsub('Hanazawa Kana', 'na', 'nya')
Hanyazawa Kanya
> string.gsub('Hanazawa Kana', 'na', function(s) return string.sub(s,1,1)..'y'..string.sub(s,2,2) end)
Hanyazawa Kanya
> string.gsub('Hanazawa Kana', '(n)(a)', function(a,b) return a..'y'..b end)
Hanyazawa Kanya
> string.gsub('Hanazawa Kana', '(n)(a)', '%1y%2')
Hanyazawa Kanya

Lua中的正則表達式

正則表達式由元字符按照規則(語法)組成。lua中的特殊字符是%.^$+-*?,一共12個。它們和一般字符按規則構成了lua的正則表達式。

元字符 描述 表達式實例 完整匹配的字串
字符
普通字符 除去%.[]()^$*+-?的字符,匹配字符本身 Kana Kana
. 匹配任意字符 Ka.a Kana
% 轉義字符,改變后一個字符的原有意思。當后面的接的是特殊字符時,將還原特殊字符的原意。%和一些特定的字母組合構成了lua的預定義字符集。%和數字1~9組合表示之前捕獲的分組 K%wna
%%na%%
(a)n%1
Kana
%na%
ana
[...] 字符集(字符類)。匹配一個包含於集合內的字符。[...]中的特殊字符將還原其原意,但有下面幾種特殊情況
1. %],%-,%^作為整體表示字符']','-','^'
2. 預定義字符集作為一個整體表示對應字符集
3. 當]位於序列的第一個字符時只表示字符']'
4. 形如[^...],[...-...]有特定的其他含義
[a%]na
[%a]na
[%%a]na
[]]na
[%]]na
[a-]na
%na
wna
wna
]na
]na
-na
[...-...] -表示ascii碼在它前一個字符到它后一個字符之間的所有字符 [a-z]a na
[^...] 不在...中的字符集合。 [^0-9]na
[^^0-9]na
Kna
Kna
重復(數量詞)
* 表示前一個字符出現0次或多次 [0-9]*
[a-z]*9*
2009
na
+ 表示前一個字符出現1次或1次以上 n+[0-9]+ n2009
? 表示前一個字符出現0次或1次 n?[0-9]+ 2009
預定義字符集
%s 空白符[ \r\n\t\v\f] an[%s]?9 an 9
%p 標點符號 an[%p]9 an.9
%c 控制字符
%w 字母數字[a-zA-Z0-9] [%w]+ Kana9
%a 字母[a-zA-Z] [%a]* Kana
%l 小寫字母[a-z] -
%u 大寫字母[A-Z] -
%d 數字[0-9] -
%x 16進制數[0-9a-fA-F] -
%z ascii碼是0的字符 -
分組
(...) 表達式中用小括號包圍的子字符串為一個分組,分組從左到右(以左括號的位置),組序號從1開始遞增。 ab(%d+)
(%d+)%1
ab233
123123
邊界匹配(屬於零寬斷言)
^ 匹配字符串開頭 ^(%a)%w* abc123
$ 匹配字符串結尾 %w*(%d)$ abc123
%b
%bxy 平衡匹配(匹配xy對)。這里的x,y可以是任何字符,即使是特殊字符也是原來的含義,匹配到的子串以x開始,以y結束,並且如果從x開始,每遇到x,計算+1,遇到y計數-1,則結束的y是第一個y使得計數等於0。就是匹配成對的符號,常見的如%b()匹配成對的括號 %b()
%d+%b()
(3+4(x*2))
2(3+4(x*2))
**備注** 1. lua不支持分組后面接重復詞(+*?),對於復雜的匹配可以用find+循環手動處理。 2. %bxy跟預定義字符集有區別,前者在[...]仍保持原意,后者則失去特殊意義 3. 上表中是lua對正則的支持,其他的正則如命名組,重復{m, n}等並不能在lua中用。注意轉義字符是%不是\

參考

  1. Lua5.1參考手冊
  2. python正則表達式指南(By AstralWind)
  3. 正則表達式30分鍾入門教程(By deerchao)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM