2011-05-12 69 views
1

好吧,我已經讀了tutorials,並且爲了現在能夠清晰地看到我而頭腦太亂了。正則表達式 - 捕獲一個重複組

我想從函數簽名中捕獲參數及其類型信息。因此,考慮這樣的簽名:

function(/*string*/a,b,c) 

我想要得到的部分是這樣的:

type: string 
param:a 
param:b 
param:c 

這也沒關係:

type: string 
param:a 
type: null (or whitespace) 
param:b 
type: null (or whitespace) 
param:c 

所以我想出了這個正則表達式這正在做重複捕捉的常見錯誤(我已明確捕捉打開):

function\(((\/\*(?<type>[a-zA-Z]+)\*\/)?(?<param>[0-9a-zA-Z_$]+),?)*\) 

問題是,我不能糾正錯誤。 。:(請幫助

+0

你在用什麼語言?如果這是一個.Net模式,那麼你很幸運。否則,它可能不可能在一個單一的步驟。 – Kobi

+0

我希望能夠在不使用.Net的情況下解決它,但是,最終我使用了.Net。另外,我已經看過Captures集合,但是我沒有將捕獲與集團關聯的可靠方法(或者我忽略了什麼?)。 – Mrchief

+0

查看已發佈的答案。有'Match.Captures'這個比較容易找到但不是很有用的,你通常需要'Group.Captures'(當然我在這裏猜測)。 – Kobi

回答

3

一般情況下,你需要兩個步驟來獲取所有數據
首先,匹配/驗證整個功能:!

function\((?<parameters>((\/\*[a-zA-Z]+\*\/)?[0-9a-zA-Z_$]+,?)*)\) 

需要注意的是,你現在parameters組所有的參數,你可以再次匹配一些模式來獲得參數的所有匹配,或者在這種情況下,分割,。 Net保留了每個組的所有捕獲的完整記錄,因此您可以使用該集合:

match.Groups["param"].Captures 

一些注意事項:

  • 如果你想獲取多種類型的,你肯定要空場比賽,所以你可以很容易地結合比賽(雖然你可以進行排序,但1對1捕獲更簡潔)。在這種情況下,你想要的可選組您的拍攝組:(?<type>(\/\*[a-zA-Z]+\*\/)?)
  • 你不必逃避斜線在.net模式 - /沒有特殊的意義有(C#/。NET沒有正則表達式的分隔符)。

下面是一個使用捕獲的例子。同樣,要點在於保持typeparam之間的關係:您想要捕獲空的類型,所以您不會丟失數量。
模式:

function 
\(
(?: 
    (?: 
     /\*(?<type>[a-zA-Z]+)\*/ # type within /* */ 
     |       # or 
     (?<type>)     # capture an empty type. 
    ) 
    (?<param> 
     [0-9a-zA-Z_$]+ 
    ) 
    (?:,|(?=\s*\)))  # mandatory comma, unless before the last ')' 
)* 
\) 

代碼:

Match match = Regex.Match(s, pattern, RegexOptions.IgnorePatternWhitespace); 
CaptureCollection types = match.Groups["type"].Captures; 
CaptureCollection parameters = match.Groups["param"].Captures; 
for (int i = 0; i < parameters.Count; i++) 
{ 
    string parameter = parameters[i].Value; 
    string type = types[i].Value; 
    if (String.IsNullOrEmpty(type)) 
     type = "NO TYPE"; 
    Console.WriteLine("Parameter: {0}, Type: {1}", parameter, type); 
} 
+0

我再次檢查。它確實捕獲了多種類型。另一個想法是捕獲括號之間的整個字符串,在逗號分割,然後循環捕獲類型和參數一個接一個。 – Mrchief

+0

@Mrchief - 對,我的壞!錯過了一個關閉paren':P' - 我已經更新了答案。你提出的另一個想法是我也建議的,儘管只是錯誤的名稱 - 我也修正了這一點。 – Kobi

+0

不知何故,我在這裏失去了我的意見!好的,我之前被第一個音符轉移了,並沒有意識到「替代」解決方案與您所展示的相同。我也嘗試過Group.Captures,但這有點冒險。它確實告訴了所有以前的捕捉,但它以平坦的方式進行。我需要能夠將一個類型與一個參數關聯起來,因此擁有一個平坦的運行列表並不是很有幫助。 Slash對我來說是新的,點注意! – Mrchief

1

您參考使用?:非捕獲,然後圍繞着它自己的組的重複採集提到的頁面。我猜他們是這樣的function\(((?:(\/\*(?<type>[a-zA-Z]+)\*\/)?(?<param>[0-9a-zA-Z_$]+),?)*)\)

我喜歡用http://gskinner.com/RegExr/測試我的表達式,但它不會顯示重複的捕獲。您可能需要循環查看返回的結構,以查看其他非.NET語言中的值。

抱歉,我無法測試更多thuroughly ...

+1

http://regexstorm.net/tester是用於測試.Net正則表達式的有用網站。還有http://regexhero.net/tester/,但它是基於Silverlight的,並不時爲你賺錢。 – Kobi

+0

不僅regexhero賺錢,偶爾會將瀏覽器關閉(Silverlight插件在長時間使用後崩潰)。正則表達式看起來很有希望。謝謝! – Mrchief

+0

@Mrchief - 你在使用什麼瀏覽器/操作系統?我還沒有看到正則表達式英雄崩潰的瀏覽器。 –

1

這已經有一段時間,因爲這個問題是積極的,但我想我終於找到了答案。

我想我一直在尋找和你一樣的情況,但是爲了和PHP一起使用,並且在另一篇文章中有一個答案,我發現使用PCRE的\K\G命令非常有效。看到艾倫摩爾的答案在這裏:PHP Regular Expression - Repeating Match of a Group

我的問題是試圖拉出一個表中的所有單元格的值,其中每行包含一個6位數字,20x 1或2位數字,和一個不相關的1或2位數字數。解決方案是:

<tr class="[^"]*">\s+<td>(\d{6})<\/td>|\G<\/td>[^<>]*+<td>\K\d{1,6}|<td>(\d{1,2})<\/td> 

非常好的解決方案,如果我這麼說,我自己!

+1

問題是每種技術都有自己的處理這種事情的利基方式。希望那裏有一些東西或正則表達式。所以現在如果有人不使用.Net或PCRE,他們會被放在冷水中。 – Mrchief