Быстрая деконструкция 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 шт):
Можно использовать 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();
Можно использовать именованные группы. Группа указывается через (?<НазваниеГруппы>метасимволы), пример (?<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]);
}