2013-01-17 49 views
2

我試圖瞭解在Ruby 1.9.3環境下.{n}?<option>:如何在Regexp中工作。但不明白下面的代碼是如何產生的輸出:如何。{n}和? <option>:在Ruby 1.9.3環境下的`Regexp`中工作環境

irb(main):001:0> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.{2}(?m:.)\Z/ 
=> ["fin\n", "fin\r\n", "find"] 
irb(main):002:0> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.{1}(?m:.)\Z/ 
=> ["fin\n", "fi\n\n"] 
irb(main):003:0> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.{1}(?m:.)\Z/ 
=> [] 
irb(main):010:0> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.(?m:.)\Z/ 
=> ["fin\n", "fi\n\n"] 
irb(main):011:0> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.(m:.)\Z/ 
=> [] 
irb(main):012:0> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.(?m:.)\z/ 
=> [] 

誰能幫我理解上面的代碼是如何工作的,以產生IRB終端所提到的輸出?

感謝,


按照@Kevin最後一段下面我試過,發現預期和理想的輸出:

irb(main):014:0> %W{fin fi\n\n \n\n fin\r\n find}.grep /f.(?m:.)\z/ 
=> ["fin"] 
irb(main):015:0> %W{fin fi\n\n \n\n fin\r find}.grep /f.(?m:.)\z/ 
=> ["fin"] 
irb(main):016:0> %W{fin fi\n \n\n fin\r\n find}.grep /f.(?m:.)\z/ 
=> ["fin", "fi\n"] 
irb(main):017:0> %W{fin fi\n \n\n fr\n find}.grep /f.(?m:.)\z/ 
=> ["fin", "fi\n", "fr\n"] 
irb(main):018:0> 

非常感謝您@Kevin 。你幫助我理解整個概念!

+2

Ruby中的'm'選項實際上是DOTALL選項,它允許'.'匹配'\ n'。 (不知道爲什麼Ruby在這一點上有所不同)。 – nhahtdh

+0

你不是指'。{n}'而不是'。(n)'(用'n'指定任何數字)? – 2013-01-17 18:34:28

+0

@Tinctorius對不起!我現在糾正了。 – DoLoveSky

回答

3

{n}表示「重複前面的原子n次」。在正則表達式中,原子是一個獨立單元。所以一個字符就是一個原子。所以是一個點。一個組也是一個原子(包含其他原子),就像一個字符類一樣。因此.{n}表示「匹配n個字符」(因爲.的意思是「匹配任何字符」)。

請注意,{n}不像反向引用,因爲它不必在每次重複上匹配相同的文本。 .{5}的行爲完全像.....

這個構造也更強大。它可能需要兩個數字,並且匹配整個範圍的重複計數。所以.{3,5}的意思是「匹配3至5個字符」。 .{3,}意思是「匹配3個或更多字符」。如果您願意,?可以用{0,1},*{0,}+{1,}代替。


?<option:實際上並不是什麼東西。它是(?<option>:<pattern>),這會打開<option>中列出的所有標記,持續時間爲<pattern>。它就像一個組,除非它實際上不創建反向引用。所以表達式(?m:.)的意思是「匹配一個字符就好像標誌m已打開」。考慮到m與nhahtdh在評論中所說的「匹配\ n」的行爲,表達.(?m:.).的意思是「匹配除換行符之外的任何字符,後跟任何字符,後面跟除換行符之外的任何字符」。

這個構造有兩個好處。首先,它允許您只將標誌應用於模式的一部分,這可能偶爾有用。其次,如果將整個模式包裝在此構造中,則無論使用何種表達式,都可以控制適用於正則表達式的標誌。當你提供正則表達式作爲用戶並且不能控制程序的源時,這很有用。


讓我們來看看你給的例子:

> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.{2}(?m:.)\Z/ 
=> ["fin\n", "fin\r\n", "find"] 

你的模式/f.{2}(?m:.)\Z/手段「比賽樓後面是任何字符2(但換行),然後是任意字符,並且錨到字符串的末尾或換行符之前「。

因此,在3場比賽的每場比賽中,finf.{2}相匹配。 (?m:.)匹配\n中的第一個,\r中的第二個和d中的第三個。並且\Z匹配第一個字符串的末尾,第二個換行符之前,第三個字符串的末尾。

fi\n\n不匹配,因爲第一\n這裏不能由..{2}沒有m標誌匹配。

> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.{1}(?m:.)\Z/ 
=> ["fin\n", "fi\n\n"] 

這裏fi匹配f.{1}在這兩種情況下。在兩種情況下(?m:.)匹配n\n\Z匹配換行符之前匹配。

fin\r\n不匹配,因爲\Z只會在字符串中的最後換行符之前匹配,而不是在CRLF對之前匹配。和find不匹配,因爲沒有什麼與d匹配。

> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.{1}(?m:.)\Z/ 
=> [] 

我想你有一個副本&粘貼錯誤在這裏。這與之前的模式和匹配相同。

> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.(?m:.)\Z/ 
=> ["fin\n", "fi\n\n"] 

這也與先前的模式相同。 ..{1}是一樣的東西。事實上,{1}可以始終從任何正則表達式中剝離,而不會更改任何內容。

> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.(m:.)\Z/ 
=> [] 

你在這個模式投下了?,改變(m:.)意義。這不再改變選項。現在它只是一個與m:.模式匹配的捕獲組,它在您的輸入中當然不會出現。

> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.(?m:.)\z/ 
=> [] 

你改變了\Z\z這裏。這兩者之間的差異是\Z可能匹配在換行符後面,但\z只能匹配字符串的末尾。如果不能在匹配的換行符之前匹配,則這裏的輸入都不匹配。但是,例如,如果您有fin(不帶換行符)或fi\n(不帶第二個換行符),它就會起作用。

+0

作爲一個新手,我無法解決我提到的代碼描述。但是我從你的帖子中得到了理論。那麼你可以用我的代碼來解釋它嗎?希望能夠在各個方向清除我的概念。請? – DoLoveSky

+0

@DoLoveSky:我剛剛編輯我的帖子來解釋你給出的每個例子。 –

+0

是的,我很高興看到你的帖子,也經歷了你發佈的理論和代碼也!非常感謝你!請成爲我的老師,:)我是這個平臺的新手,渴望從根本上學習它!希望我能做到,如果你們幫助!終於'+ 1'給你照顧我的帖子! – DoLoveSky