2011-12-11 22 views
5

比賽我想更換部分的正則表達式來代替用Ruby

This is a ![foto](foto.jpeg), here is another ![foto](foto.png) 

變換以下文本

This is a ![foto](/folder1/foto.jpeg), here is another ![foto](/folder2/foto.png) 

換句話說,我想找到的括號包圍的所有圖像路徑(該文本在Markdown語法中)並將其替換爲其他路徑。包含新路徑的字符串由單獨的real_path函數返回。

我想在塊版本中使用String#gsub。目前我的代碼看起來是這樣的:

re = /!\[.*?\]\((.*?)\)/ 

rel_content = content.gsub(re) do |path| 
    real_path(path) 
end 

與此正則表達式的問題是,它將匹配![foto](foto.jpeg),而不是僅僅foto.jpeg。我也試過其他regexen像(?>\!\[.*?\]\()(.*?)(?>\))但無濟於事。

我目前的解決方法是拆分路徑並稍後重新組裝。

是否有一個Ruby正則表達式只匹配括號內的路徑,而不是所有需要上下文的字符?

Post-answers update:這裏的主要問題是Ruby的regexen沒有辦法指定零寬度lookbehinds。最通用的解決方案是將以前的正則表達式的部分和真正的匹配部分(即/(pre)(matching-part)(post)/)之後的部分進行分組,然後重建完整的字符串。

在這種情況下的解決方案將是

re = /(!\[.*?\]\()(.*?)(\))/ 

rel_content = content.gsub(re) do 
    $1 + real_path($2) + $3 
end 

回答

5

一個快速的解決方案(根據需要調整):

s = 'This is a ![foto](foto.jpeg)' 

s.sub!(/!(\[.*?\])\((.*?)\)/, '\1(/folder1/\2)') 

p s # This is a [foto](/folder1/foto.jpeg) 
+0

也許最好的辦法是,正如你提到的,重建的字符串之前和在不同羣體的實際比賽結束後,保存部分更具可讀性並用'$ 1 + real_path($ 2)+ $ 3'重新構造最終的字符串。 – gioele

3

在你的塊,使用$1訪問第一捕獲組($2用於第二等等)。

從文檔:

在塊形式中,當前匹配字符串傳遞作爲參數,和變量如$ 1,$ 2,$`,$ &,和$」將被設置適當。該塊返回的值將被替換爲每次調用的匹配。

4

你總是可以做的兩個步驟 - 首先提取出完整的圖像表達出來,然後第二個替代鏈接:

str = "This is a ![foto](foto.jpeg), here is another ![foto](foto.png)" 

str.gsub(/\!\[[^\]]*\]\(([^)]*)\)/) do |image| 
    image.gsub(/(?<=\()(.*)(?=\))/) do |link| 
    "https://stackoverflow.com/a/new/path/" + link 
    end 
end 

#=> "This is a ![foto](/a/new/path/foto.jpeg), here is another ![foto](/a/new/path/foto.png)" 

我改變了第一個正則表達式,但是你可以使用與之前相同的那個。 image是像![foto](foto.jpeg)的圖像表達式,而link就是像foto.jpeg這樣的路徑。

[編輯]澄清:紅寶石確實有lookbehinds(他們在我的答案中):

您可以創建lookbehinds(?<=regex)正,(?<!regex)爲負,其中regex是任意的正則表達式表達符合以下條件。正則表達式在lookbehinds中必須是固定的寬度,因爲正則表達式實現的限制,這意味着它們不能包含具有未知重複次數的表達式或具有不同寬度選擇的交替表達式。如果你試圖這樣做,你會得到一個錯誤。 (雖然限制不適用於lookaheads)。

在你的情況下,[foto]部分有一個可變的寬度(foto可以是任何字符串),所以它不能因爲上述原因而進入倒映。然而,lookbehind正是我們所需要的,因爲它是一個零寬度匹配,並且我們利用第二個正則表達式中的優勢,只需要擔心(固定長度)強制開括號。

顯然你可以從這裏放real_path,但我只是想要一個可測試的例子。

我認爲這種方法更加靈活,比通過比賽組變量

+0

這就是我現在正在做的。我希望有一些我不知道在Ruby的正則表達式中創建lookbehinds的語法:(。 – gioele

+0

你可以在ruby中做向後看,但是有一個條件。 – arcresu