2013-07-07 98 views
0

返回上一頁和下一頁的話,我現在有兩個獨立的正則表達式模式來找到目標單詞+下一個字和目標字+前一個字:正則表達式 - 從比賽

string text = "Here is a test MYWORD statement for MYWORD regex"; 
string pattern = "(\\bMYWORD\\s)(\\w+)"; //MYWORD statement; MYWORD regex 
string pattern = "(\\w+)(\\s\\bMYWORD)"; //test MYWORD; for MYWORD 

是否正則表達式提供了一個巧妙的方法將二者結合起來上面的模式用於單個呼叫?

感謝

編輯: 非常感謝m.buettner和Qtax爲偉大的解釋和例子 - 非常有用!

我已經試過了一些提供的例子,這些匹配在所需的上下文中'MYWORD',但也許我還沒有足夠清楚:我試圖返回上面評論的所有短語,即:

匹配(模式)應返回以下所有字符串:

'MYWORD statement' 
'MYWORD regex' 
'test MYWORD' 
'for MYWORD' 

道歉,如果我原來的問題沒有解釋得很清楚!

+0

你想通過「單次通話」匹配/查找/提取什麼? – Bohemian

+0

更新後的問題以澄清。 – Vok

+0

@Vok所以你的意思是,如果它測試MYWORD語句,它們應該*不匹配?否則,我的答案處理這些情況。 –

回答

5

做比賽在先行中:

string pattern = @"\b(?=(\w+\s+MYWORD|MYWORD\s+\w+)\b)"; 

string[] result = Regex.Matches(text, pattern) 
         .Cast<Match>() 
         .Select(match => match.Groups[1].Value) 
         .ToArray(); 

這正則表達式匹配時不會消耗任何字符,這使得重疊匹配成爲可能。您不必擔心無限循環,因爲正則表達式引擎在開始查找下一場比賽之前會自動提前一個位置。捕捉組仍然正常工作。

如果你需要處理的開頭和喜歡提到的其他應答字符串的結束比賽,這應該這樣做:

string pattern = @"\b(?=((?:^|\w+\s+)MYWORD|MYWORD(?:\s+\w+|$))\b)"; 

更新:一個評論者問怎麼捕捉不包括目標詞的前後單詞。答案結果很簡單但並不明顯:

string pattern = @"\b(?=((\w+)\s+MYWORD|MYWORD\s+(\w+))\b)"; 

string[] result = Regex.Matches(text, pattern) 
         .Cast<Match>() 
         .Select(match => match.Groups[2].Value + match.Groups[3].Value) 
         .ToArray(); 

簡單的部分是爲單個詞添加捕獲組。非顯而易見的部分意識到,在.NET中,如果捕獲組不參與匹配,並且您訪問其屬性,則會得到一個空字符串。我們知道這兩個小組中只有一個參加了每場比賽。我們不需要知道它是哪一個,我們只是想要它的價值。連接字符串值給我們正是我們想要的。

但它變得更好:

string[] result = Regex.Matches(text, pattern) 
         .Cast<Match>() 
         .Select(match => match.Result("$2$3")) 
         .ToArray(); 

Result()方法不習慣於多,因爲.NET的正則表達式API的其餘部分被如此精心設計的,但是當它是非常有用的,它的輝煌!

+0

完全按需要執行。非常感謝。 – Vok

+0

如果我只想捕獲前一個和結束的單詞而不是搜索單詞MYWORD,該怎麼辦?防爆。聲明;正則表達式。雖然這給了:MYWORD聲明;正則表達式MYWORD; – Sanandrea

+0

@Sanandrea:有趣的問題!我已經更新了答案。 –

0

對於示例簡單的東西,因爲這會工作:

(\w+)\sMYWORD\s(\w+) 

但這需要有對MYWORD兩面話。

如果有可能無法在某些方面一個字,你可以讓他們像可選:

(?:(\w+)\s)?\bMYWORD\b(?:\s(\w+))? 

但是,這將匹配一個MYWORD與周圍無話。

如果你想與它周圍的至少一個字匹配MYWORD,你可以使用:

(?:(\w+)\sMYWORD\b(?:\s(\w+))?|\bMYWORD\s(\w+)) 

本書雖然這裏的字右邊沃爾德或者是在組2或3

+1

我不認爲.NET支持'?|' –

+0

@ m.buettner,對,謝謝指出。 – Qtax

+0

非常感謝您的回答和示例 - 我已更新原始問題以闡明我的意圖。 – Vok

2

首先,一些建議:使用逐字字符串。他們使逃逸好得多處理:

string pattern = @"(\bMYWORD\s)(\w+)"; //MYWORD statement; MYWORD regex 
string pattern = @"(\w+)(\s\bMYWORD)"; //test MYWORD; for MYWORD 

需要注意的是你的第二個圖形在錯誤的結束詞邊界:

string pattern = @"(\w+)(\sMYWORD\b)"; //test MYWORD; for MYWORD 

現在,天真的方法很簡單:

string pattern = @"(\w+)\s(MYWORD)\s(\w+)"; 

這有幾個問題。首先,它需要兩個詞在那裏,所以如果MYWORD出現字符串的一端,你將不會得到任何匹配。這可以通過允許使用錨代替文字來解決:

string pattern = @"(?:(\w+)\s|^)(MYWORD)(?:\s(\w+)|$)"; 

現在還有一個問題。比賽不能重疊。如果您有abc MYWORD def MYWORD ghi,則第二個MYWORD不匹配。如果你想允許的比賽,既不是在字符串的結束也沒有相鄰字(如foo. MYWORD bar,其中

string pattern = @"(?<=(\w+)\s|^)(MYWORD)(?=\s(\w+)|$)"; 

:您可以使用lookarounds排除從匹配周圍的話解決這個問題.「阻止」前面的單詞)。只需使lookarounds可選即可。如果他們能匹配,它們將被包括在內,如果沒有他們不會導致模式失敗:

string pattern = @"(?<=(\w+)\s)?(MYWORD)(?=\s(\w+))?"; 

Working demo.

+0

非常感謝您的回答和示例 - 我已更新原始問題以闡明我的意圖。 – Vok

+0

@martin,我們如何修改這個正則表達式來獲得匹配的關鍵字'(?<=(\ w +)\ s)?(continue)(?= \ s(\ w +))?' – Learning

+1

@Learning您應該能夠在不修改正則表達式的情況下獲得它們。檢查'match.Groups [1] .Value'和'match.Groups [3] .Value'(你可以使用他們的'Success'屬性來判斷這個單詞是否存在)。 –