入門4

核心3rs表達式。這個連接運算,再說就似乎太羅索了。把單字符順着寫就形成了一條字符線,一個字符接着一個字符。在Java中,有字符串String字符序列CharSequence),雖然都是一根繩子,但它們不是一個東西——String是類、CharSequence是接口。ok,我們不討論JavaAPI

這裏要注意的是,

在使用連接運算時記住:

    連接運算僅僅比元字符|的優先級高。

        boy是一個regex,其語義是b後面緊跟一個o再緊跟一個y。包括了元字符的時候,如b[ao]y其語義是b後面緊跟一個ao再緊跟一個y

    所有的並集(除了ba|oy形式)僅僅匹配一個單字符,例如:

        a(sd|f)g匹配Iasdgbbasgbbafgbb,而a[sd|f]g匹配asdgooasgoooafgooa|gooadg並集還有很多東西要學習的。

    關於.的問題。

        有一個典型的例子——日期的匹配說明,我們應該謹慎使用它。日期格式一般是yyyy-mm-dd當然也有yyyy.mm.dd等形式,如果使用/d/d/d/d./d/d/./d/d,雖然可以匹配用戶喜歡的日期分割符,但它也匹配2005a02b029876543210這不是我們希望的。也許使用[-/ .]頂替.比較好。它允許a dash, space, dot and forward slash作爲日期分割符。【當然它也不完善,因爲它匹配3005/13/500000/00/00。而它不匹配我寫的今天的日期格式05/2/2。事實上,regex的構造依賴於我們的目標——如果我們強制用戶使用yyyy/mm/dd格式,我們可以簡單的用:

(19|20)/d/d/(0[1-9]|1[012])/(0[1-9]|[12][0-9]|3[01]) 。】

    連接的其他形式:

        正如我們說知道的,a{3}aaa的簡寫。a{13}a|aa|aaa的簡寫。我們常常把它們與閉包運算放在一起討論。

§6 閉包

核心4r*表達式。我們首先回顧閉包運算的各種寫法,再深入理解正則表達式引擎的運行規則。

L (r*) = {ε,r,rr,……}是無窮集合,它匹配r串的任意有窮連結。

Java中:

r{ε,r }正則表達式;

r+L (r*)-{ε}正則表達式;

r{3,} L (r*)-{ε,r,rr}正則表達式;

在涉及閉包運算時,我們會遇到幾個重要概念——Greediness(貪心)、lookaheadlookbehind(瞻前顧後——前瞻、後顧)等。我們先看幾個例子:

regex

String

替換⊙

a+

saaaasgaaafga

ssgfg

ab?/w

abc aaabc gabbbf gbbaaag

 

a

far【有四個匹配項】

f⊙⊙r

[ab]+

back about bar bbb aaa bac

 

[ab]+[rc]

back about bar bbb aaa bac

 

[ab]*

back about bar bbb aaa bac

⊙⊙ck ⊙⊙out ⊙⊙r ⊙⊙ ⊙⊙ ⊙⊙c

[0-9]+

123456654321999ok

ok

[3-6]+

111333555888

 

([3-9])//1+

12355555551999ok

 

[ab]{3,}

abc aaabc gabbbf gbbaaag

 

 

 

 

解釋:單獨使用aa*很麻煩。

([3-6])//1+regex練習器與Java源程序不同!】

§7 regex引擎的機制

regex引擎是處理正則表達式的軟件,嘗試以模板去匹配給定的字符串。一般而言,我們不直接調用該引擎,而是通過一些API去使用它們。對於不同的語言和開發環境,它們不會完全一致,其中Perl 5regex是基礎,它也是使用得最廣泛的。Java語言的regexPerl 5regex flavor有一些不同。但機制是一致的。

1、匹配的兩種道路:

       有兩種regex引擎:文本引導(text-directed)引擎和regex引導的引擎。它們

2、regex引擎是急性子,它總是返回最左邊的匹配項

必須記住的非常重要的一點:regex引導的引擎總是返回最左邊的匹配項。我在前面很小心的說某個regex可以匹配那些咚咚,是因爲我們使用了一些Java語言的方法,regex引擎總是從字符串頭開始匹配(start from beginning),一旦找到了一個匹配項,它就會急急忙忙的報告說:“我找到了匹配項”。除非你要求它again

對於文本good and godregexgo{1,2}d則返回最左邊的good。我們詳細說明其過程。

regex引擎從字符串頭開始匹配,①g顯然匹配No.0g。②o{1,2}怎麼辦,引擎還有點聰明,它首先研究一下o{1,2}的語義,表示一個或兩個o,於是它首先匹配了No.1o。它發現No.2o也可以匹配,於是完成了o{1,2}的任務。③現在,引擎開始匹配dNo.3d有效。ok引擎完成了其工作。它不會再繼續匹配了。

如果我們讓它繼續匹配呢?它認爲已經走過的路不需要再重複了,於是新的開始點是No.4的空格,即 and god,①g不匹配空格,②g不匹配and、空格。③g顯然匹配No.5(新的No.)的g。引擎還有點聰明,它又研究一下o{1,2}的語義,它首先匹配了No.6o。當遇到d它知道o{1,2}的任務結束了,它發現d匹配了No.7dok引擎完成了其工作。

 

3、爲什麼regex引擎是急性子?

現在我們要求匹配一下setName方法,假設regexget|set|setName,它的返回的匹配項是什麼?yes,僅僅是set我們看看引擎是如何工作的:

①引擎首先研究了regex,把各種可能的組合瞭解清楚了。於是它開始匹配,首先它拿g匹配s,失敗了,它知道get整個失敗了。但是它知道還有其他可能的組合。②於是它開始s匹配s,成功,於是set匹配set成功。③我找到了匹配項了。它用set匹配了字符串之後,不會繼續匹配“更好”的選項。

顯然,我們沒有找到我們希望的setName方法,how to fix it?最簡單的方法是regexget|setName|set。按照上面的過程,我們能夠匹配setName。這是我們希望的。

 

4、爲什麼regex引擎有點聰明?

它有點聰明,不僅僅是說它開始匹配前,會研究一下regex。更表現在它有一點記性。regexget|setName|set要求匹配一下setGame。說說其匹配過程。前面的廢話不說了,當N匹配G時,失敗。於是regex引擎用第3個可能性s匹配No.0sregex引擎居然還知道從No.0的地方開始。現在思考,匹配setGamesetName的結果是什麼?set還是setName

 

5、Greediness(貪心)匹配:

get|setName|set可以修改一下,成get|set(Name)?它將如何匹配setName。兩個regex完全一樣。ba?運算先匹配ba,再匹配a。這就是我們所說的Greedy quantify的用法。也就是貪婪匹配或最大匹配

注意:雖然JDK文檔中,在Greedy quantify下面列出了X{n}、X{n,m},它們不過是連接而已,與最大匹配沒有關係。

X?、X*、X+、X{n,}都是最大匹配。

最大匹配與. 同時使用時,常常帶來麻煩。”.*”匹配I love “Java” and “C++”其返回的是“Java” and “C++” 。也許我們希望它匹配“Java” 。我們使用否定式取代. 的情況非常普遍,如”[^”/r/n]*”,這樣我們就可以匹配出我們希望的“Java”

對於Java的關鍵字,我們如何效驗其正確性(不考慮關鍵字和unicode的情況)?可以這樣編寫表達式[a-zA-Z_$][0-9a-zA-Z_$]*。也可以這樣編寫表達式[a-zA-Z_$][/w$]*

6、backtrack(由原路)返回

我們看看<.+>如何匹配HTML的標籤a<tr>Java </tr>cb。按照我們前面討論的方式:①<匹配No.-1的<。②.+ 進行匹配tr>Java </tr>cb,在進行最大匹配時,它把兩個>匹配了,它一直匹配所有的字符,直到文本的最後b後面不能匹配了。③這時>開始匹配,前面的最大匹配已經匹配到文本的最後b後面了,當然>匹配失敗。④regex引擎心裏明白了,那個+匹配得太多了。但regex引擎這時並不報錯,它由原路返回一個字符,它認爲.+匹配了tr>Java </tr>c於是>匹配b,失敗again;由原路返回一個字符,認爲.+匹配tr>Java </tr>>匹配c,失敗……最後終於用>匹配>,大功告成。regex引擎是急性子,它不想再退了。

現在以<.+>aa匹配a<tr>aava </tr>abb,你可以想一想,我再說,嘴巴都要破了。不說了。如果以<.+>aa.+a匹配a<tr>aava </tr>abb,罪過啊。

string

regex

a<tr>aava </tr>abb

<.+>

a<tr>aava </tr>abb

<.+>aa

a<tr>aava </tr>abb

<.+>aa.+a

a<tr>aava </tr>abb

<tr>|</tr>

 

7、最小匹配

如果想匹配出各種HTML的標籤,<tr>|</tr>顯然不行。於是,我們需要一些非貪婪匹配。

X?、X*、X+、X{n,}都是最大匹配。好,加個?就成了Laziness匹配。例如X??、X*?、X+?、X{n,}?都是最小匹配,其實X{n,m}?和X{n }?有些多餘。

string

regex

a<tr>aava </tr>abb

<.+?>

a<tr>aava </tr>abb

<.+>a?a

a<tr>aava </tr>abb

<.*?>

a<tr>aava </tr>abb

a{1,2}?

a<tr>aava </tr>abb

a{2}?

最小匹配意味者,.+? 匹配一個字符後,馬上試一試>的匹配可能,失敗了,則.+? 再匹配一個字符,再馬上試一試>的匹配可能。JDK文檔中Greedy 和 Reluctant,它是以eat一口來隱喻的,所以翻譯成貪吃和(勉強的)厭食最貼切了。不過我喜歡最大匹配、最小匹配的說法。

 

8、完全匹配

與最大匹配不同,還有一種匹配形式:X?+、X*+、X++、X{n,}+等,成爲完全匹配。它和最大匹配一樣,一直匹配所有的字符,直到文本的最後,但它不由原路返回。也就是說,一口匹配,搞不定就算了,到也乾脆,偶喜歡。

string

regex

a<tr>aava </tr>abbNo match found.

a.++b

   【空行也能匹配,ε

.*+

aabb【匹配aabbε

.*+

a<tr>aava </tr>abb

a{1,2}?

a<tr>aava </tr>abb

a{2}?

Use a possessive quantifier for situations where you want to seize all of something without ever backing off; it will outperform the equivalent greedy quantifier in cases where the match is not immediately found.

發佈了30 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章