2011-01-07 86 views
4

我通過Koans教程運行(這是一個學習的好方法)的子方法,我以前遇到過這樣的說法:紅寶石正則表達式的問題WRT的字符串

assert_equal __, "one two-three".sub(/(t\w*)/) { $1[0, 1] } 

在此聲明是__在那裏我應該把我的預期結果,使測試正確執行。我已經在這個凝視了一會兒,紛紛掏出大部分一頓,但我想不出什麼最後一位表示:

{ $1[0, 1] } 

預期的答案是:

"one t-three" 

和我所期待的:

"t-t" 

回答

11

{ $1[0, 1] }是含有表達$1[0,1]的塊。 $1[0,1]的值爲字符串$1的第一個字符,其中包含最後匹配的正則表達式的第一個捕獲組的內容。

當使用正則表達式和塊調用sub時,它將找到正則表達式的第一個匹配項,調用該塊,然後用該塊的結果替換匹配的子字符串。

所以"one two-three".sub(/(t\w*)/) { $1[0, 1] }搜索模式t\w*。這找到子字符串"two"。由於整個事件處於捕獲組中,因此該子字符串存儲在$1中。現在調用該塊並返回"two"[0,1],即"t"。所以"two"被替換爲"t",你得到"one t-three"

需要注意的重要一點是subgsub不同,它只會替換第一次出現,而不會出現該模式。

+0

完美。謝謝。我錯誤地閱讀了正則表達式,好像它是我習慣的s /.../.../語句。但是如果我理解正確的話,第二個......實際上是讓我困惑的塊中的行爲。我的理解是否正確? – jaydel 2011-01-07 14:33:13

2

@ sepp2k已經給了一個很好的答案,我只是想補充一點,你可以怎樣運用內部評級法來也許那裏自己:

>> "one two-three".sub(/(t\w*)/) { $1 } #=> "one two-three" 
>> "one two-three".sub(/(t\w*)/) { $1[0] } #=> "one t-three" 
>> "one two-three".sub(/(t\w*)/) { $1[1] } #=> "one w-three" 
>> "one two-three".sub(/(t\w*)/) { $1[2] } #=> "one o-three" 
>> "one two-three".sub(/(t\w*)/) { $1[3] } #=> "one -three" 
>> "one two-three".sub(/(t\w*)/) { $1[0,3] } #=> "one two-three" 
>> "one two-three".sub(/(t\w*)/) { $1[0,2] } #=> "one tw-three" 
>> "one two-three".sub(/(t\w*)/) { $1[0,1] } #=> "one t-three" 
1

從文檔(http://ruby-doc.org/core/classes/String.html#M001185)惡癖,這裏有回答您的兩個問題「爲什麼返回值是'一個三分之一'」和「{$ 1 [0,1]}是什麼意思?」

{$ 1 [0,1]}是什麼意思? 方法String#sub可以接受兩個參數,或者一個參數和一個塊。後者是在這裏所使用的形式,它就像方法Integer.times,這需要一個塊:

5.times { puts "hello!" } 

這樣解釋封閉大括號。

$ 1是與正則表達式的第一個捕獲組相匹配的子字符串,如here所述。 [0,1]是字符串方法「[]」,它返回基於數組值的子字符串 - 這裏是第一個字符。

放在一起{$ 1 [0,1]}是返回$ 1中第一個字符的塊,其中$ 1是上一次使用正則表達式匹配字符串時由捕獲組匹配的子字符串。

爲什麼返回值'one t-three'? 與其兄弟字符串#gsub('全局替代')不同,它的方法String#sub('substitute')將其替換爲與正則表達式匹配的字符串的第一部分替換。因此,該方法將用上述塊的值(即用其第一個字符)替換與「(t \ w *)」匹配的第一子串。由於'two'是第一個匹配的子字符串(t \ w *)(a't'後跟任意數量的字母),所以它被第一個字符't'取代。