2012-04-09 89 views
2

當我發現我的貪婪多行正則表達式在Vim中給出重疊匹配時,我很驚訝。正則表達式旨在匹配整個文本塊或連續的非空行。Vim多行正則表達式給出重疊匹配

正則表達式顯然符合我期望的所有內容(突出顯示看起來正確),但是當使用n跳到下一個匹配而不是跳到下一個塊時,它會跳到當前塊的下一行。

這裏是我用的是正則表達式(相當於(.+\n){1,}對於大多數正則表達式引擎):

\(.\+\n\)\{1,} 

這應該與至少一個非空行,並儘可能多的連續的非空行作爲可能的,這裏是一個例子文本文件:

block 1 
some stuff 
more stuff 

block 2 
foo bar 
baz qux 

施加此正則表達式(/\(.\+\n\)\{1,} + 輸入)的兩個塊被突出顯示COR後直覺,但我希望只有兩個匹配的正則表達式,每個塊一個。但是,當我按n前進到下一個正則表達式匹配時,看起來每個非空行都與正則表達式匹配,所以我的光標將從第一行開始,n將把它帶到第二行,然後是第三行,然後塊2等開始

我怎樣才能改變我的正則表達式讓我看到是每個塊的預期行爲一場比賽,這樣ň前進到下一個塊,而不是下一行?

我也有興趣知道這種行爲是否在文檔的某處,或者如果有一個選項來改變這種行爲。請注意,當在搜索/替換中使用相同的正則表達式時,行爲就是我所期望的(替換將只應用兩次,每個塊一次)。

回答

4

以下的正則表達式似乎工作:

\(\%^\|^\n\)\zs\(.\+\n\)\+ 

說明:

\(   # start of group 
    \%^   # beginning of file 
    \|   # OR 
    ^\n   # a blank line 
\)    # end of group 
\zs   # start matching here 
\(.\+\n\)\+ # at least one non-blank line 

通過使用very magic選項的長度可以減少一點:

\v(%^|^\n)\zs(.+\n)+ 

展望看看有沒有人能想出一個更短的解決方案!

zigdon的回答幫助我更好地理解爲什麼行爲是這樣的。當使用n跳轉到下一個匹配時,即使下一個匹配位置包含在上一次匹配中,它也會從光標當前位置搜索正則表達式的第一個匹配項。這就是爲什麼將正則表達式錨定到塊的開頭似乎是必要的。

感謝Nolen Royalty幫助我擺脫了第一組中的不必要的前瞻。

+2

至於我能看到'\(\%^ \ |^\ n \)\ zs \(。\ + \ n \)*'完成同樣的事情。儘管如此,它仍然令人沮喪。 – 2012-04-10 03:15:18

+1

@NolenRoyalty如果有幾個連續的空行,那麼你會匹配一些空行(零寬度匹配),但它確實使我成爲'\(\%^ \ |^\ n \)\ zs \(。\ + \ n \)\ +',它不具有相同的問題。仍然非常醜陋! – 2012-04-10 16:28:02

2

既然你的比賽說「匹配一個或多個非空行」,它肯定可以在同一段落內多次匹配。爲了解決這個問題,你可以指定光標應該放在匹配的末端 - 這意味着下一個匹配將從段落的末尾開始。您可以用\zs零寬度字符做到這一點,可以在vim:

\zs  Matches at any position, and sets the start of the match there: The 
     next char is the first char of the whole match. |/zero-width| 

那麼你的對手將變爲:

\(.\+\n\)\{1,}\zs 
+0

這允許我跳到每個塊的末尾,這對於正則表達式的簡單程度來說很好,但是如果可能的話,我希望將整個塊包含在匹配中。 – 2012-04-09 22:29:54

+0

該塊將包含在匹配中,只是光標將定位在它的末尾。或者你的意思是別的嗎? – zigdon 2012-04-09 22:37:05

+0

我的意思是「包含在比賽中」是,如果你要在搜索/替換中使用相同的正則表達式,比賽中包含的所有內容都將被替換。另一個相同的含義是「突出顯示的文字」。 – 2012-04-09 22:42:38