Lua正則表達式匹配

最近學習了一下lua的正則表達式,在此記錄一下。 爲應對複雜多變的字符串匹配需求,不少語言都有對正則表達式的支持。Lua由於要保持簡潔與小巧的設計目標,並無像perl和python同樣支持所有posix標準正則表達式規則。好比沒有{n}匹配n次的規則,字符{}都只是做爲普通字符存在,字符|在posix標準正則表達式中表示或關係,在lua的pattern中也只是做爲普通字符。python

在lua中,一個正則表達式被稱做爲pattern,pattern中一對圓括號()包含的區域被稱做爲capture.正則表達式

lua中一共有4個系統函數支持正則表達式參數,分別爲string.find,string.match,string.gmatch,string.gsubide

lua正則表達式應用的系統函數

string.find

函數的帶參形式爲string.find (s, pattern [, init [, plain]])。函數有2個必要參數s和pattern,對應源字符串和相應的正則表達式,還有2個可選參數,init表示起始匹配位置,plain表示是否將pattern中的魔法字符無效化。 函數基本目標爲,找到第一個匹配的位置。函數

來看官方文檔對此函數的說明:學習

Looks for the first match of pattern in the string s. If it finds a match, then find returns the indices of s where this occurrence starts and ends; otherwise, it returns nil. A third, optional numeric argument init specifies where to start the search; its default value is 1 and can be negative. A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain "find substring" operation, with no characters in pattern being considered magic. Note that if plain is given, then init must be given as well.If the pattern has captures, then in a successful match the captured values are also returned, after the two indices.this

函數返回匹配的第一個字符串起始位置和結尾位置,若是有capture存在,則在以後返回capture匹配的值。lua

下面的代碼演示了沒有capture存在和有capture存在時的函數返回結果:spa

print(string.find('hello world','hello')) --> 1    5
print(string.find('hello world','(%a+)')) --> 1    5   hello

對於可選參數init和plain,如下代碼做了示例:設計

print(string.find('hello (%a+) world','(%a+)',1,true)) --> 7    11

init = 1表示從第一個字符'h'開始搜索,plain = true表示pattern中的魔法字符所有無效化,以普通字符處理,所以匹配的字符從第7個字符'('開始,第11個字符')'結束。code

string.match

函數的帶參形式爲string.match (s, pattern [, init])。函數基本目標爲,尋找第一個匹配的字符串。

來看官方英文文檔對此函數的說明:

Looks for the first match of pattern in the string s. If it finds one, then match returns the captures from the pattern; otherwise it returns nil. If pattern specifies no captures, then the whole match is returned. A third, optional numeric argument init specifies where to start the search; its default value is 1 and can be negative.

此函數返回pattern的第一個匹配,若不存在,則返回nil。

下面的代碼示例了0個匹配,1個匹配,2個匹配時對應的函數返回結果:

print(string.match('hello world','renshaw')) --> nil
print(string.match('hello world','llo')) --> llo
print(string.match('hello world','(%a+)')) --> hello
  • 第一行,沒有匹配到字符串,返回nil。
  • 第二行,pattern中沒有做爲capture的一對圓括號()出現,所以,它若是匹配到字符串,會返回全匹配。
  • 第三行,%a表示匹配單個英文字母,%a+表示匹配大於一個的英文字母,直到不是英文字母的字符(在這裏是空格)出現或者到字符串結尾,(%a+)表示將其中的%a+做爲一個capture,在這次匹配中一共匹配到兩個capture,分別爲'hello''world',string.match返回第一個capture,即'hello'

此函數還接受一個可選參數init,表示字符串匹配起始位置,我的以爲這個比較雞肋,通常字符串在進行匹配以前,咱們會進行預處理,好比使用string.sub進行截斷。

如下代碼演示了init值爲3和8時的狀況,由於第8個字符爲'o'從這個字符開始匹配已經不知足'wor'的匹配要求:

print(string.match('hello world','wor',3)) --> wor
print(string.match('hello world','wor',8)) --> nil

string.gmatch

函數的帶參形式爲string.gmatch (s, pattern)。函數基本目標爲,對字符串進行全局匹配,返回匹配結果的枚舉器。

來看官方英文文檔對此函數的說明:

Returns an iterator function that, each time it is called, returns the next captures from pattern over the string s. If pattern specifies no captures, then the whole match is produced in each call.

此函數通常和for語法配合使用進行匹配結果遍歷,適用於將匹配結果進行提取的場景。

如下代碼匹配字符串中每個單詞,而後輸出:

for w in string.gmatch('hello world from lua', "%a+") do
    print(w)
end
--> hello
--> world
--> from
--> lua

string.gsub

函數的帶參形式爲string.gsub (s, pattern, repl [, n])。函數基本目標爲,對字符串進行全局匹配並替換,返回替換後的字符串。

來看官方英文文檔對此函數的說明:

Returns a copy of s in which all (or the first n, if given) occurrences of the pattern have been replaced by a replacement string specified by repl, which can be a string, a table, or a function. gsub also returns, as its second value, the total number of matches that occurred. The name gsub comes from Global SUBstitution.

If repl is a string, then its value is used for replacement. The character % works as an escape character: any sequence in repl of the form %d, with d between 1 and 9, stands for the value of the d-th captured substring. The sequence %0 stands for the whole match. The sequence %% stands for a single %.

If repl is a table, then the table is queried for every match, using the first capture as the key.

If repl is a function, then this function is called every time a match occurs, with all captured substrings passed as arguments, in order.

In any case, if the pattern specifies no captures, then it behaves as if the whole pattern was inside a capture.

If the value returned by the table query or by the function call is a string or a number, then it is used as the replacement string; otherwise, if it is false or nil, then there is no replacement (that is, the original match is kept in the string).

此函數參數s爲源字符串,pattern爲正則表達式,第三個參數repl比較複雜,它能夠是3種類型,string,table,function,匹配完成以後,函數返回替換後的字符串,還有替換的次數。最後一個可選參數n規定了替換的次數上限。

若是replfunction類型,那麼它接受n個參數(參數個數等於pattern中capture個數),分別對應pattern中capture的匹配值。

下面的代碼分別演示了1個capture和2個capture對應的repl匿名函數處理狀況:

print(string.gsub('hello world from lua','(%a+)',function(x) return x .. 'c' end)) --> helloc worldc fromc luac    4
print(string.gsub('hello world from lua','(%a+)%s*(%a+)',function(x1,x2) return x2 .. x1 end)) --> worldhello luafrom    2

若是replstring類型,則直接將匹配的值替換爲repl的值。 下面代碼將全部匹配都替換爲'c':

print(string.gsub('hello world from lua','(%a+)','c')) --> c c c c    4

以上代碼的function等效形式爲:

print(string.gsub('hello world from lua','(%a+)',function(x) return 'c' end)) --> c c c c    4

若是repltable類型,則將匹配的值k替換爲repl[k].

如下代碼演示了repl參數爲table的狀況:

repl = {hello = 'he', world = 'wo', from = 'fr'}
print(string.gsub('hello world from lua','(%a+)',repl)) --> he wo fr lua    4

由於repl['lua']nil,因此字符串lua並無被替換。 以上代碼的function等效形式爲:

repl = {hello = 'he', world = 'wo', from = 'fr'}
print(string.gsub('hello world from lua','(%a+)',function(x) return repl[x] end)) --> he wo fr lua    4

咱們須要注意string.gsub替換的是匹配的所有值。來看一個示例:

repl = { from = 'to' }
print(string.gsub('hello world {from} lua','{(%a+)}',repl)) --> hello world to lua

以上代碼不是將字符串中的'from'替換爲'to',而是將'{from}'替換爲'to',替換的是匹配的所有值。capture對應的值'from'做爲repl[k]中的k.

pattern解析

在lua的正則表達式中,規定了如下魔法字符().%+-*?[]^$,數一數,一共12個,鍵盤上的標點符號!@#$%^&*()`~-_=+{}:"<>?[];',./\|一共32個,魔法字符的比例爲37.5%,好吧,還好有些魔法字符必須以成對形式出現,咱們一個一個來介紹。

  • %這個字符,在pattern中爲轉義字符,好比%a表明全部英文字母,可是不要忘記,pattern自己也是一個lua的字符串,字符串本來的轉義字符\也是支持的,所以pattern中就有了2個轉義字符。

下面來看lua支持的%轉義有哪些:

字符 含義
%a 字母a-z,A-Z
%b %bxy,以x和y進行成對匹配
%c 控制字符ASCII碼 十進制轉義表示爲\0 - \31
%d 數字 0 - 9
%f %f[char-set],邊界匹配,前一個不在範圍內,後一個在
%g 除了空格之外的可打印字符 十進制轉義表示爲\33 - \126
%l 小寫字母 a - z
%u 大寫字母 A - Z
%s 空格 十進制轉義表示爲\32
%p 標點符號,即!@#$%^&*()`~-_=+{}:"<>?[];',./| 32個字符
%w 字母數字 a - z, A - Z, 0 - 9
%x 十六進制符號 0 - 9, a - f, A - F

除了以上表示的字符集,%與魔法字符配合使用便可達到轉義爲原生字符的效果,好比%%表示字符%,%[表示字符[, %.表示字符.等等。

  • .這個字符,在pattern中表示匹配全部字符,十進制表示爲\0 - \255
  • ()圓括號組合字符,表示一個capture.
  • []方括號組合,表示數據集。[0-7]表示八進制數據集,[01]表示二進制數據集,[AEIOUaeiou]表示元音字母數據集。
  • [^]方括號加^表示數據集的補集,全集的範圍是\0 - \255。例如,[^0-7]表示除了0-7外全部的字符,[^.]表示除了.這個字符之外全部的字符,這裏.只表明自身符號。須要注意,%S表明%s的補集,等效於[^%s],%P表明%p的補集,另外適用的還有%A %C %D %G %L %U %W %X.
  • ^&,這兩個字符是位置修飾符,若是^爲pattern的第一個字符,表明字符串必須從開頭進行匹配,若是$爲pattern的最後一個字符,表明字符串必須匹配到最末尾,若是開頭有^結尾有$,則字符串必須進行完整匹配。
  • +-*? 這四個字符爲重複匹配修飾符。說明以下:
字符 說明
+ 重複1次或者屢次 貪婪匹配
- 重複0次或者屢次 懶惰匹配
* 重複0次或者屢次 貪婪匹配
重複0次或者1次 貪婪匹配

貪婪匹配就是儘量匹配的多,懶惰匹配就是儘量匹配的少。

介紹完魔法字符,咱們進行實際應用。

  1. 匹配lua全部合法變量名稱,變量名稱必須以字母或者下劃線開頭,名稱能夠包含字母數字下劃線。(不排除關鍵字)

合法變量至少有一個字符,所以pattern值爲[_%a][_%w]*,字符集[_%a]匹配字母和下劃線,[_%w]*匹配0個或者多個字母數字下劃線。

  1. 匹配字符串中的全部數值,包括帶負號和正號的數值。

[+-]?%d+

  1. 匹配key = value形式,存入table

(%w+)%s*=%s*(%w+)

  1. 匹配[[]]或者[=[]=],包含n個等號格式的lua特殊表示字符串。

%[(=*)%[(.-)%]%1%] 5. utf8字符串反轉。

utf8.charpattern

相關文章
相關標籤/搜索