2010-01-02 78 views
5

previous question中,我問繼:使用正則表達式來匹配兩個字符串之間的字符串,而排除串

如何使用正則表達式匹配的文本是兩個字符串,其中這兩個字符串之間本身是否包含另外兩個字符串,並且內部和外部字符串之間有任意數量的文本?

我得到了這樣的回答:

/outer-start.*?inner-start(.*?)inner-end.*?outer-end/ 

我現在想知道如何從外部封閉弦和內封閉字符串之間的文本排除某些字符串。

舉例來說,如果我有這樣的文字:

外啓動一些文本內啓動文本是 - 我想做內端一些文字外-end

我想'一些文本'和'一些更多的文本'不包含'不想要的'這個詞。

換句話說,這是確定:

外啓動一些人想要的文字內啓動文本是 - 我想做內端一些有用的文字外端

但是,這是不正常:

外啓動一些不需要的文本內啓動文本是 - 我想做內端一些不需要的文本外端

或進一步解釋,上面的回答中的外部分隔符和內部分隔符之間的表達式應排除「不想要的」一詞。

使用正則表達式很容易匹配嗎?

+0

究竟是你想做些什麼? – Gumbo 2010-01-02 23:18:13

回答

5

(?:(?!unwanted).)*?替換第一個和最後一個(但不是中間).*?。 (凡(?:...)是一個非捕獲組,並(?!...)是負前瞻)。

然而,這迅速用極端情況,並警告任何真正的(例如代替)使用結束了,如果你會問什麼你真的在做(用真實的例子,即使它們是簡化的,而不是示例),你可能會得到更好的答案。

+0

這是比我更好的解決方案。 – 2010-01-02 23:11:34

0

嘗試更換最後一個。*?與:(?!(。*不想要的文本。*))

它工作?

+1

如果你不確定(即使你認爲你確定),你應該在本地(或http://codepad.org/)等網站測試你的模式,這就是爲什麼正則表達式的問題需要好的例子傳球和失敗)。 – 2010-01-02 23:21:44

1

您可以

([^u]|u[^n]|un[^w]|unw[^a]|unwa[^n]|unwan[^t]|unwant[^e]|unwante[^d])*? 

這是 「純粹」 的正則表達式的解決方案替代.*?;您正在使用的語言可能允許您使用更優雅的構造。

1

你不能用普通的正則表達式輕鬆地做到這一點,但是一些系統(比如Perl)具有擴展性,這使得它更容易。一種方法是使用負先行斷言:

/outer-start(?:u(?!nwanted)|[^u])*?inner-start(.*?)inner-end.*?outer-end/ 

關鍵是要拆了「不必要的」進(「U」後面沒有「nwanted」)或(不是「U」)。這允許模式前進,但仍然會發現並拒絕所有「不需要」的字符串。

如果你做了很多這些,人們可能會開始討厭你的代碼。 ;)

2

問一問你自己的一個更好的問題,而不是「我如何用正則表達式來做這件事?」是「我該如何解決這個問題?」。換句話說,不要試圖用正則表達式來解決一個大問題。如果你可以用正則表達式解決一半的問題,那就這樣做,然後用另一個正則表達式或其他技術解決另一半問題。

例如,將您的數據傳遞給所有匹配項,忽略不需要的文本(閱讀:獲取帶有或不帶有不需要的文本的結果)。然後,對縮減的數據集進行傳遞,並清除那些含有不需要的文本的結果。這種解決方案易於編寫,易於理解並且易於維護。對於任何你可能需要用這種方法解決的問題,它都會足夠快。

0

托拉,復活這個問題,因爲它有一個相當簡單的正則表達式的解決方案,沒有提到。這個問題是該技術的一個經典案例在這個問題解釋"regex-match a pattern, excluding..."

的想法是建立一個交替(一系列|),其中左右兩側比賽我們不是爲了得到它想要做然後... |的最後一面與我們想要的匹配,並將其捕獲到組1.如果組1被設置,則檢索它並且您有匹配。

那麼我們不想要什麼?

首先,我們想要消除整個外部區塊,如果在outer-startinner-start之間有unwanted

outer-start(?:(?!inner-start).)*?unwanted.*?outer-end 

這將是第一個|左:你可以做到這一點。它匹配整個外部塊。

第二,如果在inner-endouter-end之間有unwanted,我們想要消除整個外部塊。你可以這樣做:

outer-start(?:(?!outer-end).)*?inner-end(?:(?!outer-end).)*?unwanted.*?outer-end 

這將是中間|。它看起來有點複雜,因爲我們要確保「懶惰」的*?不會跳過一個塊的結尾到另一個塊中。

三,我們匹配並捕獲我們想要的東西。這就是:

inner-start\s*(text-that-i-want)\s*inner-end 

所以整個正則表達式,在自由空間模式是:

(?xs) 
outer-start(?:(?!inner-start).)*?unwanted.*?outer-end # dont want this 
| # OR (also don't want that) 
outer-start(?:(?!outer-end).)*?inner-end(?:(?!outer-end).)*?unwanted.*?outer-end 
| # OR capture what we want 
inner-start\s*(text-that-i-want)\s*inner-end 

this demo,看看右邊的第1組捕獲:它包含了我們想要的東西,並只適用於正確的區塊。

在Perl和PCRE中(例如在PHP中使用),你甚至不需要看組1:你可以強制正則表達式跳過我們不想要的兩個塊。正則表達式變成:

(?xs) 
(?: # non-capture group: the things we don't want 
outer-start(?:(?!inner-start).)*?unwanted.*?outer-end # dont want this 
| # OR (also don't want that) 
outer-start(?:(?!outer-end).)*?inner-end(?:(?!outer-end).)*?unwanted.*?outer-end 
) 
(*SKIP)(*F) # we don't want this, so fail and skip 
| # OR capture what we want 
inner-start\s*\Ktext-that-i-want(?=\s*inner-end) 

See demo:它直接匹配你想要什麼。

該技術在下面的問題和文章中有詳細的解釋。

參考

相關問題