2011-03-02 78 views
1

我有以下字符串:正則表達式:關於貪婪,懶惰和子串

123322

從理論上講,正則表達式1.*2應符合以下幾點:

  • 12(因爲*可以是零字符)
  • 12332
  • 123322

如果我使用正則表達式1.*2它匹配123322
使用1.*?2,它將匹配12

有沒有辦法匹配12332呢?

完美的東西會得到所有可能matchess字符串中(無論一個匹配的子串的另一

+1

你確定1。*?2匹配123322嗎?我會認爲它只匹配12. – Duniyadnd 2011-03-02 05:59:25

+0

@Duniyadnd你說得對。我修好了它。 – 2011-03-02 06:01:42

+0

如果你在字符串中多次使用'1',該怎麼辦?如果你想要一個簡單的'1. * 2'模式,你可以簡單地找到'1'的所有位置和'2'的所有位置,並選擇一個比另一個大的位置 - 沒有理由在正則表達式中那種情況。我的答案對問題有更爲一般的解決方法,但我可能已經過分複雜。 :) – Kobi 2011-03-02 07:17:05

回答

1
1(.*?2)*$ 

,你將有多次捕捉您可以連接形成所有可能的匹配

在這裏看到:regex tester

點擊「表」,擴大捕獲樹

+0

你是對的。不知道爲什麼我沒有想到它。我將與第1組中的捕獲物相匹配;) – 2011-03-04 22:22:39

2

沒有,除非有別的東西加到正則表達式來澄清它應該做的是貪婪還是不貪婪。有沒有在-betweeny;)

+0

+1在中間。 – Duniyadnd 2011-03-02 06:08:06

+0

+1,好吧,同上。 – Tim 2011-03-02 06:10:57

1

您將需要一個單獨的表達式爲每個個案,這取決於你想匹配三三兩兩的數量:

1(.*?2){1} #same as 1.*?2 
1(.*?2){2} 
1(.*?2){3} 
... 
+0

好主意。一個簡單的循環就足夠了,從1 util開始,它找不到匹配;) – 2011-03-02 07:12:13

+0

現在我看到@Kobi的答案,只有每個匹配都是獨立的(例如:'12331232':'1(。*?2) {2}'應該匹配'123312'和'1232',但是它們中有一個共同的字符串:'12')。當然,這與generl中的常規表達式有關,而與您的答案無關;) – 2011-03-02 07:39:20

1

一般情況下,這是不可能的。正則表達式匹配引擎並不是真正用於查找重疊匹配的。一個快速的解決方案是簡單地檢查手動所有子模式:

string text = "1123322"; 
for (int start = 0; start < text.Length - 1; start++) 
{ 
    for (int length = 0; length <= text.Length - start; length++) 
    { 
     string subString = text.Substring(start, length); 
     if (Regex.IsMatch(subString, "^1.*2$")) 
      Console.WriteLine("{0}-{1}: {2}", start, start + length, subString); 
    } 
} 

工作例如:http://ideone.com/aNKnJ

現在,是有可能得到一個整體的正則表達式的解決方案?大多數情況下,答案是否定的。然而,.Net確實有一些技巧可以幫助我們:它允許可變長度的後視,並允許每個捕獲組記憶所有捕獲(大多數引擎只返回每個組的最後一個匹配)。濫用這些,我們可以模擬正則表達式引擎中的一樣for循環:

string text = "1123322!"; 
string allMatchesPattern = @" 
(?<=^  # Starting at the local end position, look all the way to the back 
(
    (?=(?<Here>1.*2\G))? # on each position from the start until here (\G), 
    .      # *try* to match our pattern and capture it, 
)*      # but advance even if you fail to match it. 
) 
"; 

MatchCollection matches = Regex.Matches(text, allMatchesPattern, 
      RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace); 
foreach (Match endPosition in matches) 
{ 
    foreach (Capture startPosition in endPosition.Groups["Here"].Captures) 
    { 
     Console.WriteLine("{0}-{1}: {2}", startPosition.Index, 
          endPosition.Index - 1, startPosition.Value); 
    } 
} 

注意,目前有一個小錯誤在那裏 - 發動機不嘗試匹配的最後結局位置($),這樣你就鬆幾場比賽。目前,在字符串末尾添加!可解決該問題。

工作示例:http://ideone.com/eB8Hb

+0

這也是有效的。實際上,這與我在應用程序的另一部分中所做的非常相似,但問題在於它是'O(n^2 * m)'('m':'Regex.IsMatch'的代價) 。 'm'應該是'O(n)',因爲它是自動化的。 '1123322'沒有問題,但是從文件中提取的文本可能有點大,而且效率不高,但是如果客戶端請求它,我仍然需要做些什麼:/ – 2011-03-02 07:45:55

+0

@Oscar - 我說過,我不明白如何避免高複雜度,假設正則表達式比你描述的更復雜。你可以做一些特定於你的正則表達式來優化它,但是在更糟糕的情況下,你會創建[所有可能的子串](http://ideone.com/rH5dd),所以你可以重複它們:它沒有什麼區別,複雜性明智,如果這是你的代碼或正則表達式引擎。 (另外,我把你的問題弄錯了*理論*問題,而不是實際的問題,我認爲我不會給我的客戶端那個正則表達式':)') – Kobi 2011-03-02 08:18:14