Вы не показали нам, как вы применяете регулярное выражение, поэтому вот демонстрация, которую я взбил:
private static void ParseIt(string subject)
{
Console.WriteLine("subject : {0}\n", subject);
Regex openers = new Regex(@"[[{(]");
Regex closers = new Regex(@"[]})]");
Regex ops = new Regex(@"[*+/-]");
Regex VariableOrConstant = new Regex(@"((\d+(\.\d+)?)|\w+)" + ops + "?");
Regex splitter = new Regex(
openers + @"(?<FIRST>" + VariableOrConstant + @")+" + closers + ops + @"?" +
@"|" +
@"(?<SECOND>" + VariableOrConstant + @")" + ops + @"?",
RegexOptions.ExplicitCapture
);
foreach (Match m in splitter.Matches(subject))
{
foreach (string s in splitter.GetGroupNames())
{
Console.WriteLine("group {0,-8}: {1}", s, m.Groups[s]);
}
Console.WriteLine();
}
}
выход:
subject : 4/(2*X*[2+1])
group 0 : 4/
group FIRST :
group SECOND : 4/
group 0 : 2*
group FIRST :
group SECOND : 2*
group 0 : X*
group FIRST :
group SECOND : X*
group 0 : [2+1]
group FIRST : 1
group SECOND :
Как видите, термин [2+1]
равен , совпадающему с первой частью регулярного выражения, как вы и предполагали. Тем не менее, он ничего не может сделать с (
, потому что следующий символ скобки после него - это еще один «открывающий» ([
), и он ищет «ближе».
Вы могли бы использовать функцию "сбалансированного соответствия" .NET, чтобы сгруппировать термины, включенные в другие группы, но это не стоит усилий. Регулярные выражения не предназначены для синтаксического анализа - фактически синтаксический анализ и сопоставление регулярных выражений являются принципиально различными видами операций. И это хороший пример различия: регулярное выражение активно ищет совпадения, пропуская все, что не может использовать (например, открывающую скобку в вашем примере), но парсер должен исследовать каждый символ (даже если он просто решите проигнорировать это).
О демо: я попытался сделать минимальные функциональные изменения, необходимые для работы вашего кода (именно поэтому я не исправил ошибку при установке +
снаружи группа захвата), но я также внес несколько изменений поверхность , и они представляют собой активные рекомендации. Для остроумия:
- Всегда используйте дословные строковые литералы (
@"..."
) при создании регулярных выражений в C # (я думаю, причина очевидна).
- Если вы используете группы захвата, по возможности используйте именованные группы, но не используйте именованные группы и нумерованные группы в одном и том же регулярном выражении. Именованные группы избавляют вас от необходимости отслеживать, что и где захвачено, а опция
ExplicitCapture
избавляет вас от необходимости загромождать регулярное выражение с (?:...)
везде, где вам нужна группа без захвата.
Наконец, вся эта схема построения большого регулярного выражения из группы меньших регулярных выражений имеет очень ограниченную полезность IMO. Очень трудно отслеживать взаимодействия между частями, например, какая часть внутри какой группы. Еще одно преимущество стенографических строк C # состоит в том, что они многострочные, поэтому вы можете использовать режим свободного пробела (a.k.a. /x
или режим КОММЕНТАРИЙ):
Regex r = new Regex(@"
(?<GROUPED>
[[{(] # opening bracket
( # group containing:
((\d+(\.\d+)?)|\w+) # number or variable
[*+/-]? # and proceeding operator
)+ # ...one or more times
[]})] # closing bracket
[*+/-]? # and proceeding operator
)
|
(?<UNGROUPED>
((\d+(\.\d+)?)|\w+) # number or variable
[*+/-]? # and proceeding operator
)
",
RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace
);
Это не предназначено для решения вашей проблемы; как я уже сказал, это не работа для регулярных выражений. Это просто демонстрация некоторых полезных методов регулярных выражений.