TL; DR: Вот дополнительное решение
var str = @"You have {notifications, plural,
zero {no notifications}
one {one notification}
=42 {a universal amount of notifications}
other {# notifications}
}. Have a nice day, {name}!";
// get matches skipping nested curly braces
var matches =
Regex.Matches(str, @"{((?:[^{}]|(?<counter>{)|(?<-counter>}))+(?(counter)(?!)))}");
var results = matches.Cast<Match>().Select(m => m.Groups[1].Value).Distinct()
.Select(v => Regex.Match(v, @"^\w+").Value) // take 1st word
.ToList();
, которое приводит к (копируется из окна Visual Studio Locals при отладке)
results Count = 2 System.Collections.Generic.List<string>
[0] "notifications"
[1] "name"
... следует оригинальный ответ ...
Одна вещь, о которой следует упомянуть о текущем решении исходного вопроса:
- использование
.
не соответствует строкеразрывы, так что это одна из причин, почему он в настоящее время соответствует вложенным значениям (см. источник )
Если я понимаю вашу цель, эта статья является хорошим объяснением и демонстрацией связанныхпроблема и решение:
(в этой статье рассматривается основная проблема, отмеченная в исходном вопросе - вложенные фигурные скобки )
https://blogs.msdn.microsoft.com/timart/2013/05/14/nestedrecursive-regex-and-net-balancing-groups-detect-a-function-with-a-regex/
Из этой статьи я бы предложил следующий шаблон в качестве необязательного решения:
var str = @"You have {notifications, plural,
zero {no notifications}
one {one notification}
=42 {a universal amount of notifications}
other {# notifications}
}. Have a nice day, {name}!";
// get matches skipping nested curly braces
var matches =
Regex.Matches(str, @"{((?:[^{}]|(?<counter>{)|(?<-counter>}))+(?(counter)(?!)))}");
var results = matches.Cast<Match>().Select(m => m.Groups[1].Value).Distinct().ToList();
, что приводит к (копируется из окна Visual Studio Locals при отладке)
results Count = 2 System.Collections.Generic.List<string>
[0] "notifications, plural,\r\n zero {no notifications}\r\n one {one notification}\r\n =42 {a universal amount of notifications}\r\n other {# notifications}\r\n "
[1] "name"
(или если вы должны были распечатать эти результаты на консоли):
// Result 0 would look like:
notifications, plural,
zero {no notifications}
one {one notification}
=42 {a universal amount of notifications}
other {# notifications}
// Result 1 would look like:
name
Обновление
Я вернулся к этому и понял, что вопрос требует только отдельных слов в качестве результатов.
Затем возьмите первое слово из каждого результата
(я повторяю приведенный выше фрагмент с дополнительным оператором select, чтобы показать полное решение)
var str = @"You have {notifications, plural,
zero {no notifications}
one {one notification}
=42 {a universal amount of notifications}
other {# notifications}
}. Have a nice day, {name}!";
// get matches skipping nested curly braces
var matches =
Regex.Matches(str, @"{((?:[^{}]|(?<counter>{)|(?<-counter>}))+(?(counter)(?!)))}");
var results = matches.Cast<Match>().Select(m => m.Groups[1].Value).Distinct()
.Select(v => Regex.Match(v, @"^\w+").Value) // take 1st word
.ToList();
, что приводит к (копируется из окна Visual Studio Locals при отладке)
results Count = 2 System.Collections.Generic.List<string>
[0] "notifications"
[1] "name"
Немного больше информации
(Я только нашел это интересным и потратил немного больше времени на исследование / изучение и подумал, что стоит включить в него некоторую дополнительную информацию)
Беседы здесь и здесь включают в себя некоторые мнения за и против использования регулярных выражений для этого типа проблемы.
- Я думаю, что интересно прочитать этимнения и получить более всестороннюю точку зрения
Независимо от вышеприведенных мнений, создатели .NET сочли целесообразным реализовать определения балансирующей группы - aфункциональность, которую использует этот ответ: