你如何获得正则表达式的组名?

时间:2010-02-02 15:34:43

标签: .net regex

我有一个正则表达式,如下:

(?<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)

我会这样做,通过找到与此模式匹配的字符串并确定组名是否相等。

我知道这似乎有点费解。感谢您提供的任何帮助。

4 个答案:

答案 0 :(得分:3)

?<one-1>不起作用,因为-用于平衡组:

  

删除先前定义的组名称2的定义,并在组名称1中存储先前定义的名称2组与当前组之间的间隔。如果未定义组名称2,则匹配回溯。因为删除name2的最后一个定义会显示name2的先前定义,所以此构造允许将group name2的捕获堆栈用作计数器,以跟踪嵌套构造(如括号)。在此构造中,name1是可选的。您可以使用单引号而不是尖括号;例如,(?'name1-name2')。

您无法转义该减号,因此您必须使用其他分隔符。

答案 1 :(得分: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其余部分相同的变量命名规则,因此如果您不能将其用作合法变量名,请不要将其用作组名。

答案 2 :(得分: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库没有给我们一个简单的方法来获取组的名称,所以我们必须采用另一种方式:对于每个组名,我们检查该组是否匹配,如果是这样的话,它的名称是unescape并让调用者知道名称和捕获的子字符串。

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));
}   

答案 3 :(得分: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”组。如果匹配,那就是我们追求的群体。