LUA中關於Regex是本文要介紹的內容,LUA中的Regex跟傳統的不一樣,作者特把手冊裡一段關於正則說明抄下來,做個記錄,這些只是簡單的說明一下LUA中正則的則規,對於後面的進階應用程式以後再慢慢研究,紅色部分為LUA中常用Regex說明 . ...模式匹配函數
在string庫中功能最強大的函數是:string.find (字串尋找), string.gsub (全域字串替換), and string.gfind (全域字串尋找). 這些函數都是基於模式匹配的。
與其他指令碼語言不同的是,Lua並不使用POSIX規範的Regex(也寫作regexp)來進行模式比對(譯者:POSIX是unix的工業標準,regexp最初來源於unix,POSIX對regexp也作了規範)。主要的原因出於程式大小方面的考慮:實現一個典型的符合POSIX標準的regexp大概需要4000行代碼,這比整個Lua標準庫加在一起都大。權衡之下,Lua中的模式比對的實現只用了500行代碼,當然這意味著不可能實現POSIX所規範的所有更能。然而,Lua中的模式比對功能是很強大的,並且包含了一些使用標準POSIX模式比對不容易實現的功能。
string.find的基本應用就是用來在目標串(subject string)內搜尋匹配指定的模式的串。函數如果找到匹配的串返回他的位置,否則返回nil.最簡單的模式就是一個單詞,僅僅匹配單詞本身。比如,模式'hello'僅僅匹配目標串中的"hello"。當尋找到模式的時候,函數返回兩個值:匹配串開始索引和結束索引。
- s = "hello world"
- i, j = string.find(s, "hello")
- print(i, j) --> 1 5
- print(string.sub(s, i, j)) --> hello
- print(string.find(s, "world")) --> 7 11
- i, j = string.find(s, "l")
- print(i, j) --> 3 3
- print(string.find(s, "lll")) --> nil
例子中,匹配成功的時候,string.sub利用string.find返回的值截取匹配的子串。 (對簡單模式而言,匹配的就是其本身。)
string.find函數第三個參數是可選的:標示目標串中搜尋的起始位置。當我們想尋找目標串中所有匹配的子串的時候,這個選項非常有用。我們可以不斷的迴圈搜尋,每一次從前一次匹配的結束位置開始。下面看一個例子,下面的代碼用一個字串中所有的新行構造一個表:
- local t = {} -- table to store the indices
- local i = 0
- while true do
- i = string.find(s, "\n", i+1) -- find 'next' newline
- if i == nil then break end
- table.insert(t, i)
- end
後面我們還會看到可以使用string.gfind迭代子來簡化上面這個迴圈。
string.gsub函數有三個參數:目標串,模式串,替換串。他基本作用是用來尋找匹配模式的串,並將使用替換串其替換掉:
- s = string.gsub("Lua is cute", "cute", "great")
- print(s) --> Lua is great
- s = string.gsub("all lii", "l", "x")
- print(s) --> axx xii
- s = string.gsub("Lua is great", "perl", "tcl")
- print(s) --> Lua is great
第四個參數是可選的,用來限制替換的範圍:
- s = string.gsub("all lii", "l", "x", 1)
- print(s) --> axl lii
- s = string.gsub("all lii", "l", "x", 2)
- print(s) --> axx lii
string.gsub的第二個傳回值表示他進行替換操作的次數。例如,下面代碼湧來計算一個字串中空格出現的次數:
- _, count = string.gsub(str, " ", " ")
(注意, _ 只是一個啞元變數.)
模式
你還可以在模式串中使用字元類。字元類指可以匹配一個特定字元集合內任何字元的模式項。比如,字元類 %d 匹配任一數字. 所以你可以使用模式串'%d%d/%d%d/%d%d%d%d'搜尋dd/mm/yyyy 格式的日期 :
- s = "Deadline is 30/05/1999, firm"
- date = "%d%d/%d%d/%d%d%d%d"
- print(string.sub(s, string.find(s, date))) --> 30/05/1999
下面的表列出了Lua支援的所有字元類:
- . 任一字元
- %a 字母
- %c 控制字元
- %d 數字
- %l 小寫字母
- %p 標點字元
- %s 空白符
- %u 大寫字母
- %w 字母和數字
- %x 十六進位數字
- %z 代表0的字元
上面字元類的大寫形式表示小寫所代表的集合的補集。例如, '%A'非字母的字元:
- print(string.gsub("hello, up-down!", "%A", "."))
- --> hello..up.down. 4
(數字4不是字串結果的一部分,他是gsub返回的第二個結果,代表發生替換的次數。下面其他的關於列印gsub結果的例子中將會忽略這個數值。 ) 在模式比對中有一些特殊字元,他們有特殊的意義,Lua中的特殊字元如下:
- ( ) . % + - * ? [ ^ $
`%′用作特殊字元的逸出字元,因此 '%.' 匹配點; '%%'匹配字元 `%′ .逸出字元`%′不僅可以用來轉義特殊字元,還可以用於所有的非字母的字元。當對一個字元有疑問的時候,為安全起見請使用逸出字元轉義他。
對Lua而言,模式串就是普通的字串。他們和其他的字串沒有區別,也不會受到特殊對待。只有他們被用作模式串用於函數的時候,`%′才作為逸出字元。所以,如果你需要在一個模式串內放置引號的話,你必須使用在其他的字串中放置引號的方法來處理,使用`\′轉義引號,`\′是Lua的轉義符。你可以使用方括弧將字元類或者字元括起來建立自己的字元類(譯者:Lua稱之為char-set,就是指傳統Regex概念中的括號運算式)。比如,'[%w_]'將匹配字母數字和底線,'[01]'匹配位元字,'[%[%]]'匹配一對方括弧。下面的例子統計文本中母音字母出現的次數:
- _, nvow = string.gsub(text, "[AEIOUaeiou]", "")
在char-set中可以使用範圍表示字元的集合,第一個字元和最後一個字元之間用連字號串連表示這兩個字元之間範圍內的字元集合。大部分的常用字元範圍都已經預定義好了,所以一般你不需要自己定義字元的集合。比如,'%d'表示 '[0-9]';'%x'表示'[0-9a-fA-F]'。然而,如果你想尋找八位元,你可能更喜歡使用'[0-7]'而不是'[01234567]'。你可以在字元集(char-set)的開始處使用 `^′ 表示其補集: '[^0-7]' 匹配任何不是八位元字的字元; '[^\n]' 匹配任何非分行符號戶的字元。記住,可以使用大寫的字元類表示其補集: '%S'比'[^%s]'要簡短些.
Lua的字元類依賴於本地環境,所以'[a-z]'可能與'%l'表示的字元集不同。在一般情況下,後者包括`?? 和 `??,而前者沒有。應該儘可能的使用後者來表示字母,除非出於某些特殊考慮,因為後者更簡單、方便、更高效。
可以使用修飾符來修飾模式增強模式的表達能力,Lua中的模式修飾符有四個:
- + 匹配前一字元1次或多次
- * 匹配前一字元0次或多次
- - 匹配前一字元0次或多次
- ? 匹配前一字元0次或1次
`+′ 匹配一個或多個字元,她總是進行最長的匹配. 比如,模式串 '%a+'匹配一個或多個字母或者一個單詞 :
- print(string.gsub("one, and two; and three", "%a+", "word"))
- --> word, word word; word word
'%d+'匹配一個或多個數字 (整數):
- i, j = string.find("the number 1298 is even", "%d+")
- print(i,j) --> 12 15
`*′ 與 `+′類似, 但是他匹配一個字元0次或多次出現.一個典型的應用是匹配空白。比如,為了匹配一對圓括弧()或者( )之間的空白,可以使用'%(%s*%)'. ( '%s*'用來匹配0個或多個空白. 由於圓括弧在模式中有特殊的含義,所以我們必須使用`%′轉義他.) 再看一個例子,'[_%a][_%w]*'匹配Lua程式中的標示符:字母或者底線開頭的字母底線數字序列。
`-′與`*′一樣,都匹配一個字元的0次或多次出現,但是他進行的是最短匹配。某些時候這兩個用起來沒有區別,但有些時候結果將截然不同。比如,如果你使用模式'[_%a][_%w]-'來尋找標示符,你將只能找到第一個字母,因為'[_%w]-'永遠匹配空。另一方面,假定你想尋找C程式中的注釋,很多人可能使用 '/%*.*%*/' (也就是說 "/*" 後面跟著任意多個字元,然後跟著 "*/"). 然而,由於 '.*'進行的是最長相符,這個模式將匹配程式中第一個"/*" 和最後一個"*/"之間所有部分:
- test = "int x; /* x */ int y; /* y */"
- print(string.gsub(test, "/%*.*%*/", "<COMMENT>"))
- --> int x; <COMMENT>
然而模式 '.-'進行的是最短匹配,她會匹配"/*"開始到第一個"*/"之前的部分:
- test = "int x; /* x */ int y; /* y */"
- print(string.gsub(test, "/%*.-%*/", "<COMMENT>"))
- --> int x; <COMMENT> int y; <COMMENT>
`?′匹配一個字元0次或1次.舉個例子,假定我們想在一段文本內尋找一個整數,整數可能帶有加號或減號。 模式 '[+-]?%d+'符合我們的要求,她可以匹配 像 "-12", "23" 和 "+1009"等數字. '[+-]' 是一個匹配`+′或者 `-′的字元類;接下來的 `?′意思是匹配前面的字元類0次或者1次.
與其他系統的模式不同的是,Lua中的修飾符不能用字元類;不能將模式分組然後使用修飾符作用這個分組。比如,沒有一個模式可以匹配一個可選的單詞(除非這個單詞只有一個字母)。下面我將看到,通常你可以使用一些進階技術繞開這個限制。
以`^′開頭的模式只匹配目標串的開始部分,相似的,以`$′結尾的模式只匹配目標串的結尾部分。這不僅可以用來限制你要尋找的模式,還可以定位(anchor)模式。比如:
- if string.find(s, "^%d") then ...
- 符串s是否以數字開頭,而
- if string.find(s, "^[+-]?%d+$") then ...
檢查字串s是否是一個整數。
'%b'用來匹配對稱的字元.常寫為 '%bxy',x和y是任意兩個不同的字元;x作為匹配的開始,y作為匹配的結束。比如, '%b()'匹配以`(′開始, 以 `)′結束的字串:
- print(string.gsub("a (enclosed (in) parentheses) line",
- "%b()", ""))
- --> a line
常用的這種模式有: '%b()', '%b[]', '%b%{%}',和 '%b<>'。你也可以使用任何字元作為分隔字元。
作者提出問題的原帖:
由於看到TheoryCraft這個不錯的外掛程式,尋找網站發現一年來竟然沒人漢化,同時為了學習,決定自己動手試試,但在看代碼時遇見一些問題,特請教各位大大
首先我貼一段外掛程式中的代碼來分析:
- TheoryCraft_MeleeComboEnergyConverter = "into (.-) additional"
- TheoryCraft_MeleeComboReader = "(%d+) point(.-): (%d+)%-(%d+) damage"
- TheoryCraft_MeleeComboReplaceWith = "$points$ point%1: %2%-%3 damage"
第一行中的(.-)有點怪,是什麼意思,如果要翻譯的這句話時要如何處理,
第二行中%這個符號是否相當於轉位符/,是不是LUA中特有的替代/
第三行中$我看Regex中好象是串位符,但為什麼會放在第一個?
小結:詳解LUA中關於Regex的內容介紹完了,希望通過本文的學習能對你有所協助!