lua高級-正則表達(dá)式

模式匹配函數(shù)

在string庫中功能最強(qiáng)大的函數(shù)是:

代碼如下:

string.find(字符串查找)
string.gsub(全局字符串替換)
string.gfind(全局字符串查找)
string.gmatch(返回查找到字符串的迭代器)

這些函數(shù)都是基于模式匹配的蜓竹。與其他腳本語言不同的是蝶溶,Lua并不使用POSIX規(guī)范的正則表達(dá)式[4](也寫作regexp)來進(jìn)行模式匹配。主要的原因出于程序大小方面的考慮:實現(xiàn)一個典型的符合POSIX標(biāo)準(zhǔn)的regexp大概需要4000行代碼赊时,這比整個Lua標(biāo)準(zhǔn)庫加在一起都大吨铸。權(quán)衡之下,Lua中的模式匹配的實現(xiàn)只用了500行代碼祖秒,當(dāng)然這意味著不可能實現(xiàn)POSIX所規(guī)范的所有更能诞吱。然而,Lua中的模式匹配功能是很強(qiáng)大的竭缝,并且包含了一些使用標(biāo)準(zhǔn)POSIX模式匹配不容易實現(xiàn)的功能房维。

string.gmatch(str, pattern)

這是一個返回迭代器的函數(shù). 實際的用例如下:

代碼如下:

s = "hello world from Lua"
for w in string.gmatch(s, "%a+") do
 print(w)
end

這里是一個捕獲并將配對字符分別存到不同變量的例子:

代碼如下:

t = {}
s = "from=world, to=Lua"
for k, v in string.gmatch(s, "(%w+)=(%w+)") do
 t[k]=v
end
for k, v in pairs(t) do
 print(k, v)
end

string.gsub(str, pattern, repl, n)

string.gsub()函數(shù)根據(jù)給定的配對表達(dá)式對源字符串str進(jìn)行配對, 同時返回源字符串的一個副本, 該副本中成功配對的所有子字符串都將被替換. 函數(shù)還將返回成功配對的次數(shù).實際的替換行為由repl參數(shù)的類型決定:

當(dāng)repl為字符串時, 所有成功配對的子字符串均會被替換成指定的repl字串.

當(dāng)repl為table時, 對每個成功配對的子字符串, 函數(shù)均會試圖尋找以其為key值的table中的元素, 并返回該元素. 如果該配對包含任何捕獲信息, 則以編號為1號的捕獲作為key值進(jìn)行查找.

當(dāng)repl為函數(shù)時, 每個成功配對的子字符串均會作為參數(shù)被傳入到該函數(shù)中去.

在repl是table或函數(shù)時, 如果該table或函數(shù)返回了字串或數(shù)字的值, 這個值依然會被用于替換副本字串中的配對子字串. 如果該table/函數(shù)返回的值為空, 將不發(fā)生替換.

n參數(shù)可選, 當(dāng)它被指定時, string.gsub()函數(shù)只對源字符串中的前n個成功配對的成員進(jìn)行操作.

以下是幾個例子:

代碼如下:

> print(string.gsub("hello world", "(%w+)", "%1 %1"))
hello hello world world 2

> print(string.gsub("hello Lua", "(%w+)%s*(%w+)", "%2 %1"))
Lua hello 1

> string.gsub("hello world", "%w+", print)
hello world 2

> lookupTable = {["hello"] = "hola", ["world"] = "mundo"}
> print(string.gsub("hello world", "(%w+)", lookupTable))
hola mundo 2

string.match(str, pattern, init)

string.match()只尋找源字串str中的第一個配對. 參數(shù)init可選, 指定搜尋過程的起點, 默認(rèn)為1.

在成功配對時, 函數(shù)將返回配對表達(dá)式中的所有捕獲結(jié)果; 如果沒有設(shè)置捕獲標(biāo)記, 則返回整個配對字符串. 當(dāng)沒有成功的配對時, 返回nil.

代碼如下:

string.match("abcdaef", "a")
-> a

string.find(str, pattern, init, plain)

string.find的基本應(yīng)用就是用來在目標(biāo)串(subject string)內(nèi)搜索匹配指定的模式的串。函數(shù)如果找到匹配的串返回他的位置抬纸,否則返回nil.最簡單的模式就是一個單詞咙俩,僅僅匹配單詞本身。比如湿故,模式'hello'僅僅匹配目標(biāo)串中的"hello"阿趁。當(dāng)查找到模式的時候,函數(shù)返回兩個值:匹配串開始索引和結(jié)束索引坛猪。

代碼如下:

s = "hello world"
string.find(s, "hello")    --> 1    5
string.find(s, "world")    --> 7    11
string.find(s, "l")        --> 3    3
string.find(s, "lll")      --> nil

string.find函數(shù)第三個參數(shù)是可選的:標(biāo)示目標(biāo)串中搜索的起始位置脖阵。當(dāng)我們想查找目標(biāo)串中所有匹配的子串的時候,這個選項非常有用墅茉。我們可以不斷的循環(huán)搜索命黔,每一次從前一次匹配的結(jié)束位置開始呜呐。下面看一個例子,下面的代碼用一個字符串中所有的新行構(gòu)造一個表:

代碼如下:

local t = {}      -- 存放回車符的位置
local i = 0
while true do
    i = string.find(s, "\n", i+1)  -- 查找下一行
    if i == nil then break end
    table.insert(t, i)
end

string.sub(str,sPos,ePos)

string.gsub的功能是截取字符串悍募,他從指定起始位置截取一個字符串蘑辑。string.sub可以利用string.find返回的值截取匹配的子串。
對簡單模式而言坠宴,匹配的就是其本身

代碼如下:

s = "hello world"
local i, j = string.find(s, "hello")    --> 1    5
string.sub(s, i, j)        --> hello

string.gsub(str, sourcestr, desstr)

string.gsub的基本作用是用來查找匹配模式的串以躯,并將使用替換串其替換掉:

string.gsub函數(shù)有三個參數(shù):目標(biāo)串,模式串啄踊,替換串忧设。

代碼如下:

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

第四個參數(shù)是可選的,用來限制替換的范圍:

代碼如下:

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的第二個返回值表示他進(jìn)行替換操作的次數(shù)颠通。例如址晕,下面代碼涌來計算一個字符串中空格出現(xiàn)的次數(shù):

代碼如下:

_, count = string.gsub(str, " ", " ")

(注意,_ 只是一個啞元變量)

模式

你還可以在模式串中使用字符類顿锰。字符類指可以匹配一個特定字符集合內(nèi)任何字符的模式項谨垃。比如,字符類%d匹配任意數(shù)字硼控。所以你可以使用模式串'%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: 與任何控制符配對(例如\n)
%d: 與任何數(shù)字配對
%l: 與任何小寫字母配對
%p: 與任何標(biāo)點(punctuation)配對
%s: 與空白字符配對
%u: 與任何大寫字母配對
%w: 與任何字母/數(shù)字配對
%x: 與任何十六進(jìn)制數(shù)配對
%z: 與任何代表0的字符配對
%x(此處x是非字母非數(shù)字字符): 與字符x配對. 主要用來處理表達(dá)式中有功能的字符(^$()%.[]*+-?)的配對問題, 例如%%與%配對
[數(shù)個字符類]: 與任何[]中包含的字符類配對. 例如[%w_]與任何字母/數(shù)字, 或下劃線符號(_)配對

當(dāng)上述的字符類用大寫書寫時, 表示與非此字符類的任何字符配對. 例如, %S表示與任何非空白字符配對.例如刘陶,'%A'非字母的字符

代碼如下:

print(string.gsub("hello, up-down!", "%A", "."))
    --> hello..up.down. 4

(數(shù)字4不是字符串結(jié)果的一部分,他是gsub返回的第二個結(jié)果牢撼,代表發(fā)生替換的次數(shù)匙隔。下面其他的關(guān)于打印gsub結(jié)果的例子中將會忽略這個數(shù)值。)在模式匹配中有一些特殊字符熏版,他們有特殊的意義纷责,Lua中的特殊字符如下:

代碼如下:
( ) . % + - * ? [ ^ $

'%' 用作特殊字符的轉(zhuǎn)義字符,因此 '%.' 匹配點撼短;'%%' 匹配字符 '%'再膳。轉(zhuǎn)義字符 '%'不僅可以用來轉(zhuǎn)義特殊字符,還可以用于所有的非字母的字符曲横。當(dāng)對一個字符有疑問的時候喂柒,為安全起見請使用轉(zhuǎn)義字符轉(zhuǎn)義他。

對Lua而言禾嫉,模式串就是普通的字符串灾杰。他們和其他的字符串沒有區(qū)別,也不會受到特殊對待夭织。只有他們被用作模式串用于函數(shù)的時候吭露,'%' 才作為轉(zhuǎn)義字符吠撮。所以尊惰,如果你需要在一個模式串內(nèi)放置引號的話讲竿,你必須使用在其他的字符串中放置引號的方法來處理,使用 '' 轉(zhuǎn)義引號弄屡,'' 是Lua的轉(zhuǎn)義符题禀。你可以使用方括號將字符類或者字符括起來創(chuàng)建自己的字符類(譯者:Lua稱之為char-set,就是指傳統(tǒng)正則表達(dá)式概念中的括號表達(dá)式)膀捷。比如迈嘹,'[%w_]' 將匹配字母數(shù)字和下劃線,'[01]' 匹配二進(jìn)制數(shù)字全庸,'[%[%]]' 匹配一對方括號秀仲。下面的例子統(tǒng)計文本中元音字母出現(xiàn)的次數(shù):

代碼如下:

_, nvow = string.gsub(text, "[AEIOUaeiou]", "")

在char-set中可以使用范圍表示字符的集合,第一個字符和最后一個字符之間用連字符連接表示這兩個字符之間范圍內(nèi)的字符集合壶笼。大部分的常用字符范圍都已經(jīng)預(yù)定義好了神僵,所以一般你不需要自己定義字符的集合。比如覆劈,'%d' 表示 '[0-9]'保礼;'%x' 表示 '[0-9a-fA-F]'。然而责语,如果你想查找八進(jìn)制數(shù)炮障,你可能更喜歡使用 '[0-7]' 而不是 '[01234567]'。你可以在字符集(char-set)的開始處使用 '^' 表示其補(bǔ)集:'[^0-7]' 匹配任何不是八進(jìn)制數(shù)字的字符坤候;'[^\n]' 匹配任何非換行符戶的字符胁赢。記住,可以使用大寫的字符類表示其補(bǔ)集:'%S' 比 '[^%s]' 要簡短些白筹。

Lua的字符類依賴于本地環(huán)境徘键,所以 '[a-z]' 可能與 '%l' 表示的字符集不同。在一般情況下遍蟋,后者包括 '?' 和 '?'吹害,而前者沒有。應(yīng)該盡可能的使用后者來表示字母虚青,除非出于某些特殊考慮它呀,因為后者更簡單、方便棒厘、更高效纵穿。

可以使用修飾符來修飾模式增強(qiáng)模式的表達(dá)能力,Lua中的模式修飾符有四個:

代碼如下:

+ 匹配前一字符1次或多次
* 匹配前一字符0次或多次
- 匹配前一字符0次或多次
? 匹配前一字符0次或1次

'+'奢人,匹配一個或多個字符谓媒,總是進(jìn)行最長的匹配。比如何乎,模式串 '%a+' 匹配一個或多個字母或者一個單詞:

代碼如下:

print(string.gsub("one, and two; and three", "%a+", "word"))
    --> word, word word; word word

'%d+' 匹配一個或多個數(shù)字(整數(shù)):

代碼如下:

i, j = string.find("the number 1298 is even", "%d+")
print(i,j)    --> 12  15

'' 與 '+' 類似句惯,但是他匹配一個字符0次或多次出現(xiàn).一個典型的應(yīng)用是匹配空白土辩。比如,為了匹配一對圓括號()或者括號之間的空白抢野,可以使用 '%(%s%)'拷淘。( '%s' 用來匹配0個或多個空白。由于圓括號在模式中有特殊的含義指孤,所以我們必須使用 '%' 轉(zhuǎn)義他启涯。)再看一個例子,'[%a][%w]' 匹配Lua程序中的標(biāo)示符:字母或者下劃線開頭的字母下劃線數(shù)字序列恃轩。

'-' 與 '' 一樣结洼,都匹配一個字符的0次或多次出現(xiàn),但是他進(jìn)行的是最短匹配叉跛。某些時候這兩個用起來沒有區(qū)別补君,但有些時候結(jié)果將截然不同。比如昧互,如果你使用模式 '[%a][%w]-' 來查找標(biāo)示符挽铁,你將只能找到第一個字母,因為 '[_%w]-' 永遠(yuǎn)匹配空敞掘。另一方面叽掘,假定你想查找C程序中的注釋,很多人可能使用 '/%.%/'(也就是說 "/" 后面跟著任意多個字符玖雁,然后跟著 "/" )更扁。然而,由于 '.' 進(jìn)行的是最長匹配赫冬,這個模式將匹配程序中第一個 "/" 和最后一個 "*/" 之間所有部分:

代碼如下:

test = "int x; /* x */ int y; /* y */"
print(string.gsub(test, "/%*.*%*/", "<COMMENT>"))
    --> int x; <COMMENT>

然而模式 '.-' 進(jìn)行的是最短匹配浓镜,她會匹配 "/" 開始到第一個 "/" 之前的部分:

代碼如下:

test = "int x; /* x */ int y; /* y */"
print(string.gsub(test, "/%*.-%*/", "<COMMENT>"))
    --> int x; <COMMENT> int y; <COMMENT>

'?' 匹配一個字符0次或1次。舉個例子劲厌,假定我們想在一段文本內(nèi)查找一個整數(shù)膛薛,整數(shù)可能帶有正負(fù)號。模式 '[+-]?%d+' 符合我們的要求补鼻,它可以匹配像 "-12"哄啄、"23" 和 "+1009" 等數(shù)字。'[+-]' 是一個匹配 '+' 或者 '-' 的字符類风范;接下來的 '?' 意思是匹配前面的字符類0次或者1次咨跌。

與其他系統(tǒng)的模式不同的是,Lua中的修飾符不能用字符類硼婿;不能將模式分組然后使用修飾符作用這個分組锌半。比如,沒有一個模式可以匹配一個可選的單詞(除非這個單詞只有一個字母)寇漫。下面我將看到刊殉,通常你可以使用一些高級技術(shù)繞開這個限制殉摔。
以 '^' 開頭的模式只匹配目標(biāo)串的開始部分,相似的冗澈,以 '$' 結(jié)尾的模式只匹配目標(biāo)串的結(jié)尾部分钦勘。這不僅可以用來限制你要查找的模式陋葡,還可以定位(anchor)模式亚亲。比如:

代碼如下:

if string.find(s, "^%d") then ...

檢查字符串s是否以數(shù)字開頭,而

代碼如下:

if string.find(s, "^[+-]?%d+$") then ...

檢查字符串s是否是一個整數(shù)腐缤。

'%b' 用來匹配對稱的字符捌归。常寫為 '%bxy' ,x和y是任意兩個不同的字符岭粤;x作為匹配的開始惜索,y作為匹配的結(jié)束。比如剃浇,'%b()' 匹配以 '(' 開始巾兆,以 ')' 結(jié)束的字符串:

代碼如下:

print(string.gsub("a (enclosed (in) parentheses) line", "%b()", ""))
--> a line

常用的這種模式有:'%b()' ,'%b[]'虎囚,'%b%{%}' 和 '%b<>'角塑。你也可以使用任何字符作為分隔符。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末淘讥,一起剝皮案震驚了整個濱河市圃伶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蒲列,老刑警劉巖窒朋,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蝗岖,居然都是意外死亡侥猩,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門抵赢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拭宁,“玉大人,你說我怎么就攤上這事瓣俯〗鼙辏” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵彩匕,是天一觀的道長腔剂。 經(jīng)常有香客問我,道長驼仪,這世上最難降的妖魔是什么掸犬? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任袜漩,我火速辦了婚禮,結(jié)果婚禮上湾碎,老公的妹妹穿的比我還像新娘宙攻。我一直安慰自己,他們只是感情好介褥,可當(dāng)我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布座掘。 她就那樣靜靜地躺著,像睡著了一般柔滔。 火紅的嫁衣襯著肌膚如雪溢陪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天睛廊,我揣著相機(jī)與錄音形真,去河邊找鬼。 笑死超全,一個胖子當(dāng)著我的面吹牛咆霜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嘶朱,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼蛾坯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了见咒?” 一聲冷哼從身側(cè)響起偿衰,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎改览,沒想到半個月后下翎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡宝当,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年视事,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片庆揩。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡俐东,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出订晌,到底是詐尸還是另有隱情虏辫,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布锈拨,位于F島的核電站砌庄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜娄昆,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一佩微、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧萌焰,春花似錦哺眯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至陵珍,卻和暖如春寝杖,著一層夾襖步出監(jiān)牢的瞬間违施,已是汗流浹背互纯。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留磕蒲,地道東北人留潦。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像辣往,于是被迫代替她去往敵國和親兔院。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容