Как вы получаете название группы регулярных выражений? - PullRequest
4 голосов
/ 02 февраля 2010

У меня было регулярное выражение, вот так:

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

3 голосов
/ 02 февраля 2010

?<one-1> не работает, потому что - используется в балансировочных группах:

Удаляет определение ранее определенной группы name2 и сохраняет в группе name1 интервал между ранее определенной группой name2 и текущей группой. Если имя группы 2 не определено, сопоставление возвращается. Поскольку удаление последнего определения name2 раскрывает предыдущее определение name2, эта конструкция позволяет использовать стек захватов для группы name2 в качестве счетчика для отслеживания вложенных конструкций, таких как скобки. В этой конструкции name1 является необязательным. Вы можете использовать одинарные кавычки вместо угловых скобок; например, (? 'name1-name2').

Вы не можете избежать этого знака минус, поэтому вы должны использовать другой разделитель.

1 голос
/ 02 февраля 2010

Попробуйте использовать подчеркивание вместо тире. Когда я изменил ваше оригинальное регулярное выражение на:

(?<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 голосов
/ 02 февраля 2010

Мне непонятно, каким должен быть конечный результат, но следующее сопоставит значение с исходными именами групп. Оттуда вы можете определить, как действовать.

Дайте попробовать:

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 предоставляет простой способ извлечения имен групп из шаблона. При обращении к значению группы, которое не совпадает, возвращается пустая строка. Идея этого подхода заключается в том, чтобы проходить (через LINQ) каждое имя группы и проверять, существует ли совпадение, игнорируя группу по умолчанию «0». Если это соответствует, то это группа, за которой мы следуем.

0 голосов
/ 02 февраля 2010

Что-то вроде следующего?

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));
}   
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...