Lua的字符串匹配與正則表達式
使用lua一段時間了,簡單總結下string庫中的幾個與正則相關的函數。這些函數是find,match, gmatch和gsub。然后是lua中支持的正則。文中的例子在lua5.3的命令行中試驗過。5.1版的需要在提示符前加一個=號或加return空格。
string.find(s, pattern[, init[, plain]])
- 在字符串s中匹配pattern,如果匹配成功返回第一個匹配到的子串的起始索引和結束索引,如果pattern中有分組,分組匹配的內容也會接着兩個索引值之后返回。如果匹配失敗返回nil。
- 可選數值參數init表示從s中的哪個索引位置開始匹配,缺省值是1,可以為負索引。
- 可選布爾值參數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)) |
參考
