2010-02-02 46 views
4

我有一個正則表達式,像這樣:如何獲得正則表達式的組名?

(?<one-1>cat)|(?<two-2>dog)|(?<three-3>mouse)|(?<four-4>fish) 

當我試圖在.NET應用程序來使用這個模式,它失敗了,因爲該組的名稱包含一個 - 在它的「。

所以,作爲一種解決方法,我試圖用兩個正則表達式,第一:

(?<A>cat)|(?<Be>dog)|(?<C>mouse)|(?<D>fish) 

將與原始情況下,我一直在尋找到的組名,我可以控制的。
然後,我打算用正確的匹配組名稱從正則表達式中的一個是這樣的:

(?<A>one-1)|(?<Be>two-2)|(?<C>three-3)|(?<D>four-4) 

我會做到這一點,通過尋找匹配此模式的字符串並確定組名稱是平等的。

我知道這似乎有點複雜。感謝您提供的任何幫助。

回答

0

沿着以下方向的東西?

string[,] patterns = { 
    { "one-1", "cat" }, 
    { "two-2", "dog" }, 
    { "three-3", "mouse" }, 
    { "four-4", "fish" }, 
}; 

var regex = buildRegex(patterns); 

string[] tests = { "foo", "dog", "bar", "fish" }; 
foreach (var t in tests) { 
    var m = regex.Match(t); 
    Console.WriteLine("{0}: {1}", t, reportMatch(regex, m)); 
} 

輸出

foo: no match 
dog: two-2 = dog 
bar: no match 
fish: four-4 = fish

首先我們逃離組名,並將它們與圖案結合建立一個Regex實例。任何非單詞字符都將替換爲序列_nnn_,其中nnn是其UTF-32值。

private static Regex buildRegex(string[,] inputs) 
{ 
    string regex = ""; 
    for (int i = 0; i <= inputs.GetUpperBound(0); i++) { 
     var part = String.Format(
      "(?<{0}>{1})", 
      Regex.Replace(inputs[i,0], @"([\W_])", new MatchEvaluator(escape)), 
      inputs[i,1]); 

     regex += (regex.Length != 0 ? "|" : "") + part; 
    } 

    return new Regex(regex); 
} 

private static string escape(Match m) 
{ 
    return "_" + Char.ConvertToUtf32(m.Groups[1].Value, 0) + "_"; 
} 

對於比賽的.NET庫並沒有給我們一個簡單的方法來得到一個組的名稱,所以我們必須走另外一條路:每個組的名稱,我們檢查組是否匹配,如果所以不要使用它的名字,並讓調用者知道名字和捕獲的子字符串。

private static string reportMatch(Regex regex, Match m) 
{ 
    if (!m.Success) 
     return "no match"; 

    foreach (var name in regex.GetGroupNames()) { 
     if (name != "0" && m.Groups[name].Value.Length > 0) 
      return String.Format(
         "{0} = {1}", 
         Regex.Replace(name, @"_(\d+)_", 
          new MatchEvaluator(unescape)), 
         m.Groups[name].Value); 
    } 

    return null; 
} 

private static string unescape(Match m) 
{ 
    return Char.ConvertFromUtf32(int.Parse(m.Groups[1].Value)); 
} 
+1

你可能想看看另一種獲取組名的方法:http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.getgroupnames.aspx – 2010-02-02 20:50:12

+0

@Ahmad謝謝!更新。 – 2010-02-02 21:18:05

+0

我去了這個變化。謝謝 – Irwin 2010-02-09 13:20:46

1

嘗試使用下劃線而不是破折號。當我改變了原來的正則表達式:

(?<one_1>cat)|(?<two_2>dog)|(?<three_3>mouse)|(?<four_4>fish) 

我可以使用網上論壇[「one_1」]值匹配的組。

編輯:例:

string pattern = "(?<one_1>cat)|(?<two_2>dog)|(?<three_3>mouse)|(?<four_4>fish)"; 
string[] inputs = new[]{"cat", "horse", "dog", "dolphin", "mouse", "hamster", "fish"}; 
string[] groups = new[]{"one_1", "two_2", "three_3", "four_4"}; 

foreach(string input in inputs) 
{ 
    Match oMatch = Regex.Match(input, pattern, RegexOptions.IgnoreCase); 

    Console.WriteLine("For input: {0}", input); 

    foreach(string group in groups) 
    { 
     Console.WriteLine("Group {0}:\t{1}", group, oMatch.Groups[group].Value);  
    } 
    Console.WriteLine("----------"); 
} 

使用破折號,你是在開始的時候會導致其無法找到組名稱。我假設它使用與.NET其餘部分相同的變量命名規則,因此如果您不能將其用作合法變量名稱,請不要將其用作組名稱。

+0

我不能更改破折號。或者說,我不想在參數上施加這個約束。 – Irwin 2010-02-02 15:47:45

3

?<one-1>不工作,因爲-用於到平衡基團:

刪除先前定義的組NAME2和存儲在組的定義NAME1先前定義的NAME2組和當前組之間的間隔。如果沒有定義組名稱2,則匹配回溯。由於刪除名稱2的最後一個定義顯示了name2的前一個定義,因此此構造允許將組2的捕獲堆棧用作計數器,以便跟蹤嵌套構造(如圓括號)。在這個結構中,name1是可選的。您可以使用單引號代替尖括號;例如(?'name1-name2')。

你不能逃避那個減號,所以你必須使用另一個分隔符。

0

我不清楚你想要的最終結果是什麼,但下面將映射值到原始組名。從那裏你可以確定如何進行。

試試這個:

var map = new Dictionary<string, string>() 
{ 
    {"A", "one-1"}, 
    {"B", "two-2"}, 
    {"C", "three-3"}, 
    {"D", "four-4"} 
}; 

string[] inputs = { "cat", "dog", "mouse", "fish", "bird" }; 
string pattern = "(?<A>cat)|(?<B>dog)|(?<C>mouse)|(?<D>fish)"; 

Regex rx = new Regex(pattern); 
foreach (string input in inputs) 
{ 
    Match m = rx.Match(input); 
    if (m.Success) 
    { 
     string groupName = rx.GetGroupNames() 
          .Where(g => g != "0" && m.Groups[g].Value != "") 
          .Single(); 
     Console.WriteLine("Match: {0} -- Group name: {1} -- Corresponds to: {2}", 
          input, groupName, map[groupName]); 
    } 
    else 
    { 
     Console.WriteLine("Failed: {0}", input); 
    } 
} 

Regex.GetGroupNames method提供了一個簡單的方法來從圖案中提取組名。當引用一個不匹配的組值時,它將返回一個空字符串。這種方法背後的想法是循環(LINQ到)每個組名,並檢查匹配是否存在,而忽略默認的「0」組。如果它匹配,那麼這就是我們之後的組。