Быстрая деконструкция Regex

Описание

У меня есть результат Regex-а Match match, группы которой я хочу разобрать на части вот так:

  • первую группу пропустить,
  • вторую группу присвоить к переменной instruction,
  • все остальные присвоить к переменной args.

В JavaScript это выглядело бы так:

const match = /example/.exec(`example`);
if (match === null) return;
const [, instruction, ...args] = match;

Хотел бы сделать такую же деконструкцию и в C#:

Match match = new Regex(@"example").Match("example");
if (!match.Success) return;
(_, Group instruction, Group[] ..args) = match.Groups;

Вопрос

Слышал, что в последних версиях C# появилось много синтаксического сахара и даже оператор ... Попробовал, везде получил ошибку.
Как все-таки выполнить эту деконструкцию?


Ответы (2 шт):

Автор решения: Alexander Petrov

Можно использовать pattern matching, а именно List patterns.
Однако, это выглядит несколько неуклюже из-за того, что это нужно использовать в условном операторе if/switch.

var groups = new string[] { "a", "b", "c", "d" };

if (groups is [_, var ins, .. var arg])
{
    Console.WriteLine(ins); // b
    Console.WriteLine(string.Join(",", arg)); // c,d
}

Можно просто использовать доступ по индексу и LINQ:

var ins2 = groups[1];
var arg2 = groups.Skip(2); //.ToArray();
→ Ссылка
Автор решения: Vladislav Mikkoev

Можно использовать именованные группы. Группа указывается через (?<НазваниеГруппы>метасимволы), пример (?<FirstWord>\\w+)\\s(?<SecondWord>\\w+) — непрерывное количество алфавитно-цифровых символов (не менее одного), потом идёт пробел, потом тоже любое непрерывное количество алфавитно-цифровых символов (не менее одного). Обращение к группе происходит через индексатор, принимающий строковый параметр у GroupCollection (свойство Groups). Пример кода:

var regex = new Regex("(?<FirstWord>\\w+)\\s(?<SecondWord>\\w+)");
var match = regex.Match(@"ПервоеСлово ВтороеСлово");

if (match.Success)
{
    var firstWord = match.Groups["FirstWord"].Value;
    var secondWord = match.Groups["SecondWord"].Value;
    Console.WriteLine(firstWord);
    Console.WriteLine(secondWord);
}
else
{
    Console.WriteLine("Неудача");
}

Можно ещё даже так, из-за перегруженной версии метода ToString у класса Capture:

var regex = new Regex("(?<FirstWord>\\w+)\\s(?<SecondWord>\\w+)");
var match = regex.Match(@"ПервоеСлово ВтороеСлово");

if (match.Success)
{
    Console.WriteLine(match.Groups["FirstWord"]);
    Console.WriteLine(match.Groups["SecondWord"]);
}

По поводу деконструирования объекта, у класса GroupCollection не определён метод Deconstruct, поэтому нет возможности сделать то, что вы хотите. Если хочется сделать какой-то кастом, то это будет костыль и он будет выглядеть вот так:

static void Main(string[] args)
{
    var regex = new Regex("(?<FirstWord>\\w+)\\s(?<SecondWord>\\w+)");
    var match = regex.Match(@"ПервоеСлово ВтороеСлово");

    if (match.Success)
    {
        var (_, secondWord) = Deconstruct(match.Groups);
        Console.WriteLine(secondWord.Value);
    }
    else
    {
        Console.WriteLine("Неудача");
    }
}

private static (Capture, Capture) Deconstruct(GroupCollection groups)
{
    return (groups[1], groups[2]);
}
→ Ссылка