2013-07-19 41 views
7

我有一個正則表達式。它包含一個必需的命名捕獲組和一些可選的命名捕獲組。它捕獲單獨的匹配並將這些部分解析爲我需要的指定組。可重複的複雜正則表達式,帶點'。'定界分隔符

除了現在我需要它重複。

本質上,我的正則表達式表示(可能)更長的字符串中的單個原子單位。而不是完全匹配我的正則表達式,目標字符串通常包含正則表達式的重複實例,由點''分隔。字符。

例如,如果這是我的正則表達式捕獲:<some match>

實際字符串可能看起來像任何一個:

  • <some match>
  • <some match>.<some other match>
  • <some match>.<some other match>.<yet another match>

修改原始正則表達式以解釋重複模式而忽略點的最簡單方法是什麼?

我不確定它是否真的需要,但這裏是我用來捕捉單個細分的正則表達式。再次,我想加強這個以考慮可選的附加分段。我希望每個細分都顯示爲結果集中的另一個「匹配」;

^(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])?(?:\[(?<index2>[0-9]+)\])?(?:\[(?<index3>[0-9]+)\])?$ 

它旨在解析一個類路徑,最多三個可選索引訪問器。 (即「member.sub_member[0].sub_sub_member[0][1][2]」)

我懷疑答案是涉及先行還是後退,對此我並不完全熟悉。

我目前使用String.Split分隔字符串段。但是我想,如果正則表達式的增強功能足夠簡單,那麼我會跳過額外的分割步驟,並重新使用正則表達式作爲驗證機制。

編輯:

如齒輪額外的扳手,我想禁止任何點「」字符從字符串的開頭或結尾開始。它們只應作爲路徑段之間的分隔符存在。

+2

一個簡單的方法是將字符串拆分爲'.',然後在每個字符串上運行您的正則表達式。 –

+0

我目前這樣做。我想如果對正則表達式的增強足夠簡單,我可以放棄字符串.Split,並且還可以在解析字符串之前對其進行驗證。 – BTownTKD

+0

換句話說,你正在尋找從字符串的開頭到尾部用點分隔的連續匹配,沒有別的,不是嗎? –

回答

2

你並不需要使用任何環視。您可以將(^|\.)放在主圖案前,然後在+之後。這將允許您創建重複的.分隔序列。我也建議你將<index>組合成一個簡單的捕捉組(我用*來匹配任意數量的索引,但是你可以簡單地使用{0,3}來匹配最多3個)。最終的模式將是:

(?:(?:^|\.)(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])*)+$ 

例如:

var input = "member.sub_member[0].sub_sub_member[0][1][2]"; 
var pattern = @"(?:(?:^|\.)(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])*)+$"; 
var match = Regex.Match(input, pattern); 
var parts = 
    (from Group g in match.Groups 
    from Capture c in g.Captures 
    orderby c.Index 
    select c.Value) 
    .Skip(1); 

foreach(var part in parts) 
{ 
    Console.WriteLine(part); 
} 

將輸出:

member 
sub_member 
0 
sub_sub_member 
0 
1 
2 

更新:該模式將確保該字符串不能有任何前導或尾隨點。這是一個龐然大物,但它應該工作:

^(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\]){0,3}(?:\.(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\]){0,3})*$ 

或者這一次,雖然我也有放棄對我的「不看人,變通」的想法:

^(?!\.)(?:(?:^|\.)(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\]){0,3})*$ 
+0

我喜歡簡化。我可能需要將尾部*更改爲{0,3},因爲存在3個索引訪問器的硬性限制。但那不是重點。你設定的(^ | \。)圖案是否確保沒有頭部或尾部點?即點應該只存在於路徑段之間 - 不在開始或結束處。 – BTownTKD

+0

插入正則表達式後,它似乎只生成一個匹配。它「吃掉」所有前面的路徑段,並將整個事件作爲單個「成員」組處理。 – BTownTKD

+0

@BTownTKD你是對的,它確實允許領先的''。(我會努力解決這個問題),但它肯定不應該'吃'前面的部分。你可能只需要調整你如何迭代結果,因爲每個組現在可以有多個捕獲。 –

1

最簡單的方法很可能是在'。'上使用string.Split來拆分字符串。字符,然後將正則表達式應用於結果數組中的每個元素。長期來看,正則表達式會有一些殘酷的表現和潛在的前瞻/背後的問題。

1

試試這個獸出來:

(?<=^|\.)?((?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])?(?:\[(?<index2>[0-9]+)\])?(?:\[(?<index3>[0-9]+)\])?)(?=\.){0,3}$? 

下面是一個示例控制檯應用程序:

class Program 
{ 
    public static void Main() 
    { 
     var input = @"member.sub_member[0].sub_sub_member[0][1][2]"; 
     var matches = Regex.Matches(input, @"(?<=^|\.)?((?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])?(?:\[(?<index2>[0-9]+)\])?(?:\[(?<index3>[0-9]+)\])?)(?=\.){0,3}$?"); 
     foreach (Match match in matches) 
     { 
      Console.Write("Member: {0} Index {1} Index2: {2} Index3 {3}\r\n", 
       match.Groups["member"].Value, 
       match.Groups["index"].Value, 
       match.Groups["index2"].Value, 
       match.Groups["index3"].Value); 
     } 
    } 
} 
1

您可以使用\G就一定要具有連續的結果和前瞻,以檢查模式後面跟着一個點或字符串的結尾:

var pattern = @"(?:^|\G\.)(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])?(?:\[(?<index2>[0-9]+)])?(?:\[(?<index3>[0-9]+)])?(?=\.|$)"; 

從MSDN:與\G「比賽必須開始在上一場比賽結束的位置「

+0

我怎麼能改變這個禁止點'。'在開始或結束的字符?我想確保它們只存在於路徑段之間。 – BTownTKD

+0

我試圖將這個插入我的測試程序(從我的答案),它顯示''成員''作爲整個比賽 –