lua 中的正則表達(dá)式

模式匹配函數(shù)

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

string.find (字符串查找)
string.gsub (全局字符串替換)
string.gfind (全局字符串查找)

這些函數(shù)都是基于模式匹配的昧港。

與其他腳本語(yǔ)言不同的是,Lua并不使用POSIX規(guī)范的正則表達(dá)式(也寫作regexp)來(lái)進(jìn)行模式匹配(譯者:POSIX是unix的工業(yè)標(biāo)準(zhǔn),regexp最初來(lái)源于unix,POSIX對(duì)regexp也作了規(guī)范)裸违。主要的原因出于程序大小方面的考慮:實(shí)現(xiàn)一個(gè)典型的符合POSIX標(biāo)準(zhǔn)的regexp大概需要4000行代碼厌秒,這比整個(gè)Lua標(biāo)準(zhǔn)庫(kù)加在一起都大村缸。權(quán)衡之下,Lua中的模式匹配的實(shí)現(xiàn)只用了500行代碼痢虹,當(dāng)然這意味著不可能實(shí)現(xiàn)POSIX所規(guī)范的所有更能被去。然而,Lua中的模式匹配功能是很強(qiáng)大的奖唯,并且包含了一些使用標(biāo)準(zhǔn)POSIX模式匹配不容易實(shí)現(xiàn)的功能惨缆。

string.find
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.find的基本應(yīng)用就是用來(lái)在 s 內(nèi)搜索匹配指定的模式(第二個(gè)參數(shù))的串。函數(shù)如果找到匹配的串返回他的位置丰捷,否則返回nil.例如最簡(jiǎn)單的模式就是一個(gè)單詞坯墨,僅僅匹配單詞本身。比如病往,模式'hello'僅僅匹配目標(biāo)串中的"hello"畅蹂。當(dāng)查找到模式的時(shí)候,函數(shù)返回兩個(gè)值:匹配串開始索引和結(jié)束索引荣恐。
例子中液斜,匹配成功的時(shí)候累贤,string.sub利用string.find返回的值截取匹配的子串。 (對(duì)簡(jiǎn)單模式而言少漆,匹配的就是其本身臼膏。)

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

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
    t.insert(t, i)
end

后面我們還會(huì)看到可以使用string.gfind迭代子來(lái)簡(jiǎn)化上面這個(gè)循環(huán)。

string.gsub

string.gsub函數(shù)有三個(gè)參數(shù):目標(biāo)串脆贵,模式串医清,替換串。他基本作用是用來(lái)查找匹配模式的串卖氨,并將使用替換串其替換掉:

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
第四個(gè)參數(shù)是可選的会烙,用來(lái)限制替換的范圍: 
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的第二個(gè)返回值表示他進(jìn)行替換操作的次數(shù)。例如筒捺,下面代碼用來(lái)計(jì)算一個(gè)字符串中空格出現(xiàn)的次數(shù):

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

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

模式

你還可以在模式串中使用字符類柏腻。字符類指可以匹配一個(gè)特定字符集合內(nèi)任何字符的模式項(xiàng)。
比如系吭,字符類 %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 控制字符
%d 數(shù)字
%l 小寫字母
%p 標(biāo)點(diǎn)字符
%s 空白符
%u 大寫字母
%w 字母和數(shù)字
%x 十六進(jìn)制數(shù)字
%z 代表0的字符

上面字符類的大寫形式表示小寫所代表的集合的補(bǔ)集五嫂。例如, '%A'非字母的字符:

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

數(shù)字4不是字符串結(jié)果的一部分,他是gsub返回的第二個(gè)結(jié)果肯尺,代表發(fā)生替換的次數(shù)沃缘。下面其他的關(guān)于打印gsub結(jié)果的例子中將會(huì)忽略這個(gè)數(shù)值。

在模式匹配中有一些特殊字符蟆盹,他們有特殊的意義孩灯,Lua中的特殊字符如下:
( ) . % + - * ? [ ^ $
'%'用作特殊字符的轉(zhuǎn)義字符,因此 '%.' 匹配點(diǎn); '%%'匹配字符 '%′ .轉(zhuǎn)義字符'%'不僅可以用來(lái)轉(zhuǎn)義特殊字符逾滥,還可以用于所有的非字母的字符峰档。當(dāng)對(duì)一個(gè)字符有疑問的時(shí)候,為安全起見請(qǐng)使用轉(zhuǎn)義字符轉(zhuǎn)義他寨昙。

對(duì)Lua而言讥巡,模式串就是普通的字符串。他們和其他的字符串沒有區(qū)別舔哪,也不會(huì)受到特殊對(duì)待欢顷。只有他們被用作模式串用于函數(shù)的時(shí)候,'%'才作為轉(zhuǎn)義字符捉蚤。所以抬驴,如果你需要在一個(gè)模式串內(nèi)放置引號(hào)的話炼七,你必須使用在其他的字符串中放置引號(hào)的方法來(lái)處理,使用'/'轉(zhuǎn)義引號(hào)布持,'/'是Lua的轉(zhuǎn)義符豌拙。你可以使用方括號(hào)將字符類或者字符括起來(lái)創(chuàng)建自己的字符類(譯者:Lua稱之為char-set,就是指?jìng)鹘y(tǒng)正則表達(dá)式概念中的括號(hào)表達(dá)式)题暖。比如按傅,'[%w_]'將匹配字母數(shù)字和下劃線,'[01]'匹配二進(jìn)制數(shù)字胧卤,'[%[%]]'匹配一對(duì)方括號(hào)唯绍。下面的例子統(tǒng)計(jì)文本中元音字母出現(xiàn)的次數(shù):
_, nvow = string.gsub(text, "[AEIOUaeiou]", "")
在char-set中可以使用范圍表示字符的集合,第一個(gè)字符和最后一個(gè)字符之間用連字符連接表示這兩個(gè)字符之間范圍內(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]'要簡(jiǎn)短些.
Lua的字符類依賴于本地環(huán)境湿滓,所以'[a-z]'可能與'%l'表示的字符集不同。在一般情況下舌狗,后者包括?′ 和?′叽奥,而前者沒有。應(yīng)該盡可能的使用后者來(lái)表示字母痛侍,除非出于某些特殊考慮朝氓,因?yàn)楹笳吒?jiǎn)單、方便主届、更高效赵哲。
可以使用修飾符來(lái)修飾模式增強(qiáng)模式的表達(dá)能力,Lua中的模式修飾符有四個(gè):

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

'+' 匹配一個(gè)或多個(gè)字符君丁,她總是進(jìn)行最長(zhǎng)的匹配. 比如枫夺,模式串 '%a+'匹配一個(gè)或多個(gè)字母或者一個(gè)單詞 :

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

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

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

'*' 與 '+'類似, 但是他匹配一個(gè)字符0次或多次出現(xiàn).一個(gè)典型的應(yīng)用是匹配空白。比如绘闷,為了匹配一對(duì)圓括號(hào)()或者( )之間的空白橡庞,可以使用'%(%s%)'. ( '%s'用來(lái)匹配0個(gè)或多個(gè)空白. 由于圓括號(hào)在模式中有特殊的含義较坛,所以我們必須使用'%′轉(zhuǎn)義他.)
再看一個(gè)例子,'[%a][%w]'匹配Lua程序中的標(biāo)示符:字母或者下劃線開頭的字母下劃線數(shù)字序列扒最。
'-'與'*′一樣燎潮,都匹配一個(gè)字符的0次或多次出現(xiàn),但是他進(jìn)行的是最短匹配扼倘。某些時(shí)候這兩個(gè)用起來(lái)沒有區(qū)別确封,但有些時(shí)候結(jié)果將截然不同。比如再菊,如果你使用模式'[%a][%w]-'來(lái)查找標(biāo)示符,你將只能找到第一個(gè)字母秉剑,因?yàn)?[_%w]-'永遠(yuǎn)匹配空侦鹏。另一方面略水,假定你想查找C程序中的注釋劝萤,很多人可能使用 '/%
.%/' (也就是說(shuō) "/" 后面跟著任意多個(gè)字符床嫌,然后跟著 "/"). 然而厌处,由于 '.'進(jìn)行的是最長(zhǎng)匹配阔涉,這個(gè)模式將匹配程序中第一個(gè)"/" 和最后一個(gè)"*/"之間所有部分:

test = "int x; /* x */   int y; /* y */"
print(string.gsub(test, "/%*.*%*/", "<COMMENT>"))
    --> int x; <COMMENT>
然而模式 '.-'進(jìn)行的是最短匹配洒敏,她會(huì)匹配"/*"開始到第一個(gè)"*/"之前的部分: 
test = "int x; /* x */   int y; /* y */"
print(string.gsub(test, "/%*.-%*/", "<COMMENT>"))
   --> int x; <COMMENT>   int y; <COMMENT>

'?'匹配一個(gè)字符0次或1次.舉個(gè)例子凶伙,假定我們想在一段文本內(nèi)查找一個(gè)整數(shù),整數(shù)可能帶有正負(fù)號(hào)显押。 模式 '[+-]?%d+'符合我們的要求,她可以匹配 像 "-12", "23" 和 "+1009"等數(shù)字. '[+-]' 是一個(gè)匹配'+′或者 '-′的字符類挖息;接下來(lái)的 '?'意思是匹配前面的字符類0次或者1次.
與其他系統(tǒng)的模式不同的是兽肤,Lua中的修飾符不能用字符類;不能將模式分組然后使用修飾符作用這個(gè)分組电禀。比如尖飞,沒有一個(gè)模式可以匹配一個(gè)可選的單詞(除非這個(gè)單詞只有一個(gè)字母)。下面我將看到沮明,通常你可以使用一些高級(jí)技術(shù)繞開這個(gè)限制珊擂。
以'^′開頭的模式只匹配目標(biāo)串的開始部分,相似的挚歧,以`$′結(jié)尾的模式只匹配目標(biāo)串的結(jié)尾部分吁峻。這不僅可以用來(lái)限制你要查找的模式用含,還可以定位(anchor)模式矮慕。比如:

if string.find(s, "^%d") then ...
檢查字符串s是否以數(shù)字開頭,而
if string.find(s, "^[+-]?%d+$") then ...
檢查字符串s是否是一個(gè)整數(shù)痴鳄。

'%b'用來(lái)匹配對(duì)稱的字符.常寫為 '%bxy',x和y是任意兩個(gè)不同的字符缸夹;x作為匹配的開始,y作為匹配的結(jié)束痪寻。比如, '%b()'匹配以'(′開始橡类, 以 ')′結(jié)束的字符串:

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

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

參考文章:
lua 中的正則表達(dá)式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末取劫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌义辕,老刑警劉巖璧函,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件基显,死亡現(xiàn)場(chǎng)離奇詭異撩幽,居然都是意外死亡库继,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)清钥,“玉大人谱净,你說(shuō)我怎么就攤上這事“萦ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵琅催,是天一觀的道長(zhǎng)居凶。 經(jīng)常有香客問我,道長(zhǎng)藤抡,這世上最難降的妖魔是什么侠碧? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮缠黍,結(jié)果婚禮上弄兜,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好挨队,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布谷暮。 她就那樣靜靜地躺著,像睡著了一般盛垦。 火紅的嫁衣襯著肌膚如雪湿弦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天腾夯,我揣著相機(jī)與錄音颊埃,去河邊找鬼。 笑死蝶俱,一個(gè)胖子當(dāng)著我的面吹牛班利,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播榨呆,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼罗标,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了积蜻?” 一聲冷哼從身側(cè)響起闯割,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎竿拆,沒想到半個(gè)月后宙拉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丙笋,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年谢澈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片御板。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锥忿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出稳吮,到底是詐尸還是另有隱情缎谷,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布灶似,位于F島的核電站,受9級(jí)特大地震影響瑞你,放射性物質(zhì)發(fā)生泄漏酪惭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一者甲、第九天 我趴在偏房一處隱蔽的房頂上張望春感。 院中可真熱鬧,春花似錦、人聲如沸鲫懒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)窥岩。三九已至甲献,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間颂翼,已是汗流浹背晃洒。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留朦乏,地道東北人球及。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像呻疹,于是被迫代替她去往敵國(guó)和親吃引。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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

  • Lua 5.1 參考手冊(cè) by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,793評(píng)論 0 38
  • 模式匹配函數(shù) 在string庫(kù)中功能最強(qiáng)大的函數(shù)是: 代碼如下: 這些函數(shù)都是基于模式匹配的刽锤。與其他腳本語(yǔ)言不同的...
    passiony閱讀 15,991評(píng)論 1 9
  • Python中的正則表達(dá)式(re) import rere.match #從開始位置開始匹配际歼,如果開頭沒有則無(wú)re...
    BigJeffWang閱讀 7,081評(píng)論 0 99
  • 基礎(chǔ)知識(shí) Lua中的string和c#中相同,string類型的值一旦改變姑蓝,便要為新值開辟空間鹅心,并指向此空間。也就...
    Charon_ted閱讀 1,054評(píng)論 0 1
  • 忘了從哪收集的資料了纺荧,放這兒旭愧,以備不時(shí)之需。 只能輸入數(shù)字:"^[0-9]*$"宙暇。 只能輸入n位的數(shù)字:"^\d{...
    study_monkey閱讀 1,403評(píng)論 0 7