2013-03-05 76 views
0

我使用的是GNU sed版本4.2.1,我試圖編寫一個非貪婪的SED正則表達式來提取由另外兩個字符串分隔的字符串。這是很容易當的定界字符串是單個字符:如何編寫SED正則表達式來提取由另一個字符串分隔的字符串?

s:{\([^}]*\)}:\1:g 

在該示例中的字符串被分隔「{」在左邊和「}」就對了。

如果限定字符串是多個字符,說「{{{」和「}}}」我可以調整上述表達式所示:

s:{{{\([^}}}]*\)}}}:\1:g 

所以中心表達式匹配不包含任何的「 }}}'關閉字符串。但是這隻適用於匹配字符串根本不包含'}'的情況。喜歡的東西:

{{{cannot match {this broken} example}}} 

不會工作,但

{{{can match this example}}} 

確實工作。當然

s:{{{\(.*\)}}}:\1:g 

始終工作,但是貪婪,所以不適合在同一行上出現多個模式。

我明白[^a]意味着任何東西,除了a[^ab]意味着任何東西,除了ab所以,儘管它出現的工作,我不認爲[^}}}]是排除連續3個字符序列的正確方法。

那麼如何寫一個SED的正則表達式匹配一個字符串,該字符串是另外兩個字符串的分隔符?

回答

1

你是對的,[^}}}]不起作用。否定字符類可以匹配任何不是其中的字符的東西。重複字符不會改變邏輯。所以你寫的和[^}]一樣。 (當表達式中沒有大括號時,很容易看出它爲什麼會起作用)。

在Perl兼容的正則表達式,你可以使用?做出*+非貪婪:

s:{{{(.*?)}}}:$1:g 

這將始終與開幕{{{後的第一個}}}

但是,this is not possible in Sed。事實上,我認爲Sed在這場比賽中沒有任何辦法。唯一的另一種方式是使用先進的功能,比如Sed,它也沒有。

可以很容易地在一個sed狀方式使用Perl與-pe選擇,這導致其採取的代碼的命令行的單個線(-e),並自動循環每個線和打印結果(-p) 。

perl -pe 's:{{{(.*?)}}}:$1:g' 

-i選項就地文件的編輯也有用,但要確保你的正則表達式是正確的第一!

欲瞭解更多信息,請參閱perlrun

+0

感謝您的回答 - 這正是我所懷疑的,因爲我知道sed不能展望未來。我發現我不需要在你的例子中轉義捕獲組:''s:{{{(。*?)}}}:$ 1 <:g''(實際上,當我這樣做時,工作)。 – starfry 2013-03-05 13:00:44

+0

@starfry,哎呀,你是對的捕獲組。這是一個錯字。 – 2013-03-05 13:27:48

0

隨着sed,你可以這樣做:

sed -e :a -e 's/\(.*\){{{\(.*\)}}}/\1\2/ ; ta' 

有了:

{{{can match this example}}} {{{can match this 2nd example}}} 

這給:

can match this example can match this 2nd example 

這不是懶惰匹配,但從右到更換我們可以利用sed的貪婪。

相關問題