摘 要:在編寫處理字符串的程序或網(wǎng)頁時(shí),經(jīng)常會(huì)有查找符合某些復(fù)雜規(guī)則的字符串的需要。正則表達(dá)式就是用于描述這些規(guī)則的語法。本文通過與、或、非這三種邏輯運(yùn)算來闡述正則表達(dá)式的正確使用方法。
關(guān)鍵詞:正則表達(dá)式;與;或;非
中圖分類號(hào):TP393.08
正則表達(dá)式是對(duì)字符串操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個(gè)“規(guī)則字符串”,這個(gè)“規(guī)則字符串”用來表達(dá)對(duì)字符串的一種過濾邏輯。在計(jì)算機(jī)科學(xué)中,是指一個(gè)用來描述或者匹配一系列符合某個(gè)句法規(guī)則的字符串的單個(gè)字符串。我們可以歸納為三種邏輯,即與、或、非。
一般來說,正則表達(dá)式千變?nèi)f化,總是這三種邏輯的組合。比如匹配雙引號(hào)字符串\"quoted string\"。
與:首尾的雙引號(hào)字符必須出現(xiàn)。
或:兩個(gè)雙引號(hào)之間的字符個(gè)數(shù)是不確定的(如果是空字符串””,則兩個(gè)雙引號(hào)之間沒有字符)。
非:兩個(gè)雙引號(hào)之間不能出現(xiàn)雙引號(hào)字符。
再比如匹配html中的open-tag(比如
與:首尾必須分別是<和>,如果是close-tag,則<之后必須出現(xiàn)/。
或:<和>之間必須出現(xiàn)至少一個(gè)字符(<>不是一個(gè)合法的tag)。
非:<之后不能是/字符,如果是open-tag,<之后不能出現(xiàn)/。
下面我們來解析三種邏輯的對(duì)策。
1 與
“與”是正則表達(dá)式中最普通的邏輯關(guān)系。一般來說,如果正則表達(dá)式中的元素沒有任何量詞(quantifier,比如*、?、+)修飾,就是“與”關(guān)系。比如『<』,就表示“這里必須出現(xiàn)<字符”;『cat』,就表示“這里必須依次出現(xiàn)c、a、t,3個(gè)字符”,但有時(shí)“必須出現(xiàn)”的是若干個(gè)元素,但它們之間并不相連。
2 或
“或”是正則表達(dá)式中最靈活的邏輯關(guān)系。正則表達(dá)式能應(yīng)對(duì)各種不同的文本,“或”功能不可或缺。
如果“或”的意思是,元素可以出現(xiàn),也可以不出現(xiàn),或者出現(xiàn)的次數(shù)不確定,可以用量詞來表示“或”關(guān)系。比如表達(dá)式『a?』,表示在此處,字符a可以出現(xiàn),也可以不出現(xiàn);表達(dá)式『(ab)+』,表示在此處,字符串a(chǎn)b必然要出現(xiàn)1次,也可以出現(xiàn)無限多次。
如果“或”的意思是,可以出現(xiàn)的是某幾個(gè)元素中的一個(gè),則應(yīng)該使用字符組或者多選結(jié)構(gòu)。當(dāng)元素都是單個(gè)字符時(shí),就應(yīng)該使用字符組『[…]』:比如匹配單詞cat或者cut,除去開頭的a、結(jié)尾的t是固定的,之中“或許出現(xiàn)a,或許出現(xiàn)u”,所以應(yīng)當(dāng)使用字符組『[au]』,整個(gè)正則表達(dá)式就是『c[au]t』。當(dāng)元素不只單個(gè)字符(只要有一個(gè)元素不只單個(gè)字符)時(shí),就應(yīng)該使用多選結(jié)構(gòu)『(…|…)』:比如不但要匹配單詞cat或者cut,還要匹配單詞chart、conduct和court,除去開頭的a、結(jié)尾的t是固定的,之中“或許出現(xiàn)a,或許出現(xiàn)u,或許出現(xiàn)har,或許出現(xiàn)onduc,或許出現(xiàn)our”,這時(shí)候就應(yīng)該使用多選結(jié)構(gòu)『(a|u|har|onduc|our)』,整個(gè)正則表達(dá)式就是『c(a|u|har|onduc|our)t』。
當(dāng)然,多選分支也可以表示字符組,比如『[au]』就可以表示為『(a|u)』,兩者的功能是完全等價(jià)的。
在實(shí)踐中,“與”和“或”經(jīng)常同時(shí)出現(xiàn),比如這個(gè)URL pattern:/foo/bar_tmp.php。foo是模塊名,bar是控制器名,tmp是方法名。合法的URL并不要求3個(gè)名字每次都出現(xiàn),可以只出現(xiàn)控制器名(/foo),也可以只出現(xiàn)控制器名和模塊名(/foo/bar.php),也可以3者都出現(xiàn)(/foo/bar_tmp.php)。
這里的模塊名、控制器名、方法名,都可以用『[a-z]+』匹配,我們暫用foo、bar、tmp代替對(duì)應(yīng)的表達(dá)式。
與:/foo必須出現(xiàn)。
或:/bar和.php是可選出現(xiàn)的,但必須同時(shí)出現(xiàn),或同時(shí)不出現(xiàn)(與)/foo必須出現(xiàn),這很好表示,暫且不去管它;/bar和.php如果出現(xiàn),必須同時(shí)出現(xiàn),所以它們應(yīng)該作為一個(gè)元素,寫作『(/bar.php)』;整個(gè)元素可選出現(xiàn),所以給它添加量詞,得到『(/bar.php)?』;最后,在/bar和.php都出現(xiàn)的前提下,_tmp才可以出現(xiàn),所以將『(_tmp)?』填充到『(/bar.php)?』,得到『(/bar(_tmp)?.php)?』,最后加上開頭的/foo,整個(gè)表達(dá)式就是『(/bar(_tmp)?.php)?』。
3 非
“非”是正則表達(dá)式中最難處理的邏輯關(guān)系。因?yàn)闆]有直接對(duì)應(yīng)的結(jié)構(gòu)。最簡(jiǎn)單的“非”,意思是此處不能出現(xiàn)某個(gè)字符,似乎用排除型字符組『[^…]』就可以解決。我們?nèi)匀慌ecat和cut的例子,如果仍然希望匹配c開頭、t結(jié)尾的單詞,但不希望匹配cut,可以寫成『c[^u]t』,即:最開頭的字母是c,之后是一個(gè)不為u的字符,之后是t。沒錯(cuò),它確實(shí)不會(huì)匹配cut,也可以匹配cat。但是,chart、conduct、court等等,它也沒法匹配,因?yàn)閇^u]的意思是:匹配一個(gè)不是u的字符。
分析要實(shí)現(xiàn)的功能:
與:以c開頭,以t結(jié)尾。
或:c和t之間可以出現(xiàn)的字母必須多于一個(gè),沒有上限。
非:c和t之間不能只有一個(gè)字符u。
在c之間的位置向后看,不能出現(xiàn)cut。這一點(diǎn),正好對(duì)應(yīng)否定順序環(huán)視(positive look-ahead)功能,『(?!cut)』就是用來進(jìn)行這種判斷的,它判斷之后的字符串能不能由cut匹配,但并不真正真正進(jìn)行匹配,也不會(huì)移動(dòng)“當(dāng)前位置”。所以我們將它放在表達(dá)式的最開頭,得到『(?!cut)c[a-z]+t』。這個(gè)表達(dá)式的邏輯是:只有在當(dāng)前位置右側(cè)字符串不能由cut匹配的情況下,才從這里開始,向右嘗試用c[a-z]+t。
如果我們更進(jìn)一步,需要排除掉cat和cut,可以把否定順序環(huán)視改為『(?!c[au]t)』。這樣就能保證,匹配到的肯定不是cat或者cut。
更復(fù)雜一點(diǎn),如果我們要驗(yàn)證這樣一個(gè)字符串:它全部由小寫字母構(gòu)成,長(zhǎng)度不超過12位,其中不能包含unfavored或者unwanted。也可以照章處理,先匹配“長(zhǎng)度不超過12位”的小寫字母『[a-z]{,12}』,然后寫出匹配“不需要匹配內(nèi)容”的正則表達(dá)式,『(unfavored|unwanted)』,再用否定順序環(huán)視將它“排除”即可,只是這次要注意,不能直接寫『(??。╱nfavored|unwanted))』,因?yàn)樗荒芘懦海╱nfavored|unwanted)』出現(xiàn)在字符串開頭的情況,為了排除它出現(xiàn)在字符串中的情況,我們要把否定順序環(huán)視改為『(?![a-z]*(unfavored|unwanted))』,這樣就確保完整的“排除”,整個(gè)表達(dá)式就是『(?![a-z]*(unfavored|unwanted))[a-z]{,12}』。
正則表達(dá)式中的“非”,除去能用排除型字符組直接表示的,復(fù)雜一點(diǎn)的“非”邏輯都是按照這樣的思路進(jìn)行的:先用一個(gè)正則表達(dá)式準(zhǔn)確匹配需要“排除”的字符串,再用環(huán)視功能排除掉它——“非”確實(shí)是正則表達(dá)式中,最難處理的邏輯關(guān)系,好在它并不復(fù)雜,而且,除去一些比較古老的工具(比如Apache 1.3),現(xiàn)在各種工具和語言,基本都支持這種功能。
參考文獻(xiàn):
[1]張樹壯,羅浩,方濱興.面向網(wǎng)絡(luò)安全的正則表達(dá)式匹配技術(shù)[J].軟件學(xué)報(bào),2011(08).
[2]鐘京馗.JAVA中的正則表達(dá)式及其應(yīng)用[J].電腦編程技巧與維護(hù),2005(06).
[3]杜冬梅,許彩欣,蘇健.淺談?wù)齽t表達(dá)式在web系統(tǒng)中的應(yīng)用[J].計(jì)算機(jī)系統(tǒng)應(yīng)用,2007(08).
[4]鄧緒斌,朱揚(yáng)勇.ReDE:一個(gè)基于正則表達(dá)式的生物數(shù)據(jù)抽取方法[J].計(jì)算機(jī)研究與發(fā)展,2005(12).
作者簡(jiǎn)介:周興旺(1979.11-),男,揚(yáng)州人,講師,碩士,研究方向:計(jì)算機(jī)網(wǎng)絡(luò)技術(shù)、數(shù)據(jù)挖掘、教育教學(xué)管理等。
作者單位:南通農(nóng)業(yè)職業(yè)技術(shù)學(xué)院,江蘇南通 226007
基金項(xiàng)目:江蘇高校哲學(xué)社會(huì)科學(xué)研究項(xiàng)目(項(xiàng)目編號(hào):NO.2014SJD641)。