2012-02-02 82 views
0

我是新來的正則表達式,並爭取找到匹配的話,其在括號{ }之間這是詞和第一個字母是大寫的,第二個是小寫希望指針一切。所以我想忽略任何數字還包含數字之間找到{}

{ test1, Test2, Test, 1213, Tsg12, Tesgd} , test5, test6, {abc, Abc} 

所以我只是想帶回了比賽的話:

Test 
Tesgd 
Abc 

我已經看了使用\b\w對於那些話約束和[Az]爲上依次降低,但不知道如何只得到這是支架之間只爲好詞。

+1

是否可以嵌套{}方括號?例如:{{aa,bb} cc},dd – 2012-02-03 00:01:59

+0

「第二個是小寫字母」是否總是有第二個字母?第三個字母是大寫還是小寫? – 2012-02-03 00:02:50

+0

有可能有嵌套的括號,是的,對不起,我應該說,在第一個大寫字母后面的所有其他字母應該是小寫字母 – user1186144 2012-02-03 00:04:43

回答

3

這裏是您的解決方案:

Regex r = new Regex(@"(?<={[^}]*?({(?<depth>)[^}]*?}(?<-depth>))*?[^}]*?)(?<myword>[A-Z][a-z]+?)(?=,|}|\Z)", RegexOptions.ExplicitCapture); 
string s = "{ test1, Test2, Test, 1213, Tsg12, Tesgd} , test5, test6, {abc, Abc}"; 
var m = r.Matches(s); 
foreach (Match match in m) 
    Console.WriteLine(match.Groups["myword"].Value); 

我以爲這是OK的,但裏面沒有最深層次paranthesis匹配。讓我們分解一下正則表達式。 AAA意味着任意表達。 WWW是指任意的標識符(字母序列)

  • .是任意字符
  • [A-Z]是因爲你可以猜測任何大寫字母。
  • [^}]是任何字符,但}
  • ,|} | \ Z表示,}
  • *?字符串結束意味着賽前0或多次,但什麼來懶洋洋地(做一個最小的匹配如果可能,吐出你吞下的東西儘可能多的匹配)
  • (?<=AAA)意味着AAA應該在左邊匹配,然後才能真正嘗試 來匹配某些東西。
  • (?=AAA)意味着AAA應與右側 你真正匹配的東西之後。
  • (?<www>AAA)意味着匹配AAA,給你匹配的名字WWW的字符串。僅用於ExplicitCapture選項。
  • (?<depth>)匹配的一切,但也推「深度」在堆棧上。
  • (?<-depth>)匹配所有內容,但也彈出堆棧的「深度」。如果堆棧爲空,則失敗。

我們使用最後兩項來確保我們在一個paranthesis內。如果沒有嵌套的假設或匹配只發生在最深的假設中,那將會簡單得多。

正則表達式適用於您的示例,可能沒有錯誤。不過我傾向於同意別人,你不應該盲目地複製你無法理解和維護的東西。正則表達式是美好的,但只有當你願意花時間學習它們。

編輯:我糾正了正則表達式中的一個粗心的錯誤。 (在兩個地方與[^}]*?取代.*?故事的士氣:。這是很容易的正則表達式的引入錯誤

+0

這不起作用。在OP的示例字符串中,沒有用大括號括起來的單詞是'test5'和'test6',它們也不符合其他標準:它們不以大寫字母開頭,並且它們包含數字。用「Testx」替換其中一個,即使它沒有用大括號括起來,也會看到它被標記爲匹配。 – 2012-02-03 01:28:15

+0

糟糕。我糾正了它。它現在應該工作。謝謝。 – 2012-02-03 02:01:29

+0

+1。很好的詳細解釋。儘量不要在現實生活中如此:)。 – 2012-02-03 02:29:50

-1

不要在兩個步驟的過濾。使用正則表達式

@"\{(.*)\}" 

拉出托架之間的片,和正則表達式

@"\b([A-Z][a-z]+)\b" 

拉出每個以大寫字母開頭,後面跟着小寫的話字母。

+3

失敗。第一個正則表達式貪婪,會匹配整個字符串。試試'@「\ {([^}] *)\}」' – 2012-02-02 23:53:10

0

在回答你原來的問題,我就提出了這樣的正則表達式:

\b[A-Z][a-z]+\b(?=[^{}]*}) 

最後一部分是一個正數lookahead;它記錄了當前的匹配位置,試圖匹配所包含的子表達式,然後將匹配位置返回到它開始的位置,在這種情況下,它從剛剛匹配的單詞的末尾開始並且吞噬儘可能多的字符,只要它們不是{}。如果之後的下一個字符是},這意味着這個詞在一對大括號裏面,所以這個lookahead成功了。如果下一個字符是{,或者因爲它位於字符串的末尾而沒有下一個字符,則向前看失敗,並且正則表達式引擎將繼續嘗試下一個單詞。

不幸的是,這是行不通的,因爲(正如你在評論中提到的那樣)大括號可能是嵌套的。匹配任何種類的嵌套或遞歸結構從根本上與正則表達式的工作方式不兼容。很多正則表達式都提供這種功能,但它們傾向於以不同的方式去實現,而且它總是很難看。下面是我會怎麼做這在C#中,使用Balanced Groups

Regex r = new Regex(@" 
     \b[A-Z][a-z]+\b 
     (?! 
     (?> 
      [^{}]+ 
      | 
      { (?<Open>) 
      | 
      } (?<-Open>) 
     )* 
     $ 
     (?(Open)(?!)) 
    )", RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace); 
    string s = "testa Testb { Test1 Testc testd 1Test } Teste { Testf {testg Testh} testi } Testj"; 
    foreach (Match m in r.Matches(s)) 
    { 
    Console.WriteLine(m.Value); 
    } 

輸出:

Testc 
Testf 
Testh 

我依然採用了先行,但這次我用一個計數器命名爲Open組跟蹤相對於右花括號數量的花括號。如果當前正在考慮的字未包含在大括號中,則在向前看到字符串末尾($)時,Open的值將爲零。否則,無論是正面還是負面,conditional construct-(?(Open)(?!)) - 都會將其解釋爲「true」,並嘗試匹配(?!)。沒有任何東西是負面的,這是保證失敗的;總是有可能無所適從。

嵌套與否,不需要使用逆序;向前看就足夠了。大多數口味對後視都有嚴格限制,甚至沒有人會認爲嘗試將它們用於這樣的工作。 .NET沒有這樣的限制,所以你可能這樣做的後顧之憂,但它沒有多大意義。爲什麼所有這些工作在其他條件 - 大寫首字母,無數字等等 - 測試時便宜得多?