2017-02-17 37 views
0

Я хочу проанализировать следующий текст с помощью Regex с помощью тега функции.Вложенные теги Regex

Anwers: <function>2+2 
       <function>1+3</function> 
     </function>. 
Thanks for your time. 
<function>sayGoodbye() 
     <function>10*10</function> 
     writeYourName() 
</function> 

Ниже рекурсивный метод, который должен преобразовать данный текст в:

Ответы: 44. Спасибо за ваше время. До свидания 100 рексов.

private static readonly string TagFormulaStart = "<function>"; 
private static readonly string TagFormulaEnd = "</function>"; 

public static string Calculate(string formula) 
{ 
    var pattern = string.Format("{0}(((.|\r|\n)*?)){1}", TagFormulaStart, TagFormulaEnd); 
    var matches = Regex.Matches(formula, pattern); 

    if (matches.Count == 0) 
    { 
     return formula; 
    } 
    else 
    { 
     var firstAppearanceOfTAG = matches[0].ToString(); 
     var formulaToCalculate = firstAppearanceOfTAG.Replace(TagFormulaStart, string.Empty).Replace(TagFormulaEnd, string.Empty); 
     var result = BgProcessorLib.Evaluator.EvaluateString(formulaToCalculate, null, false); 

     formula = formula.Replace(firstAppearanceOfTAG, result); 

     return Calculate(formula); 
    } 
} 

Проблема заключается в том, что мое регулярное выражение /<function>(((.|\r|\n)*?))<\/function>/igm в случае вложенных тегов остановится при первом появлении конца функции тега.

Прикрепленный файл, чтобы сделать его более четким.

enter image description here

+1

Если вы работаете в C# и используете .NET regex, тестирование регулярного выражения на сайте, которое поддерживает только JS-regex, бессмысленно. –

+2

Вы уверены, что хотите разбора XML с регулярными выражениями? Есть много готовых «колес», называющих парсеры XML. –

+0

@NikolayProkopyev это не XML. – POIR

ответ

3

Хотя я бы не рекомендовал решить это с помощью регулярных выражений, если вы действительно хотите, вы должны сказать ваш Regex не включать другой открывающий тег, например:

<function>((?!<function>).)*?<\/function> 

Предупреждение : ужасное исполнение, только для образовательных целей!

Кроме того, вы должны избежать ввод:

var pattern string.Format("{0}((?!{0}).)*?{1}", 
    Regex.Escape(TagFormulaStart), 
    Regex.Escape(TagFormulaEnd)); 

var matches = Regex.Matches(formula, pattern, RegexOptions.Singleline); 

Это не будет приходиться много реалистичных сценариев использования, поэтому еще раз: я бы не рекомендовал использовать RegEx в данном конкретном случае ,

Online-Demo
Fiddle

+3

« Образовательный »намек: никогда не используйте'.. \ R | \ n) *? 'Внутри шаблона. Просто используйте 'RegexOptions.Singleline' и просто' .' будет соответствовать любому символу. –

+0

@ WiktorStribiżew Право! Я полностью забыл об этом ^^ –

0

О XML подходе.

Сначала сделайте свой исходный код действительным XML, т. Е. Добавьте окруженный корневой тег <root> Answer <function... </root>.

Затем используйте анализатор как Linq

XElement root = XElement.Parse(sourceString); 

foreach (var funct in root.Descendants("function")).ToList() { 
    var evaluated = evaluate(funct.InnerText); // evaluate should be defined before 
    funct.InnerText = evaluated; 
} 

var result = root.ToString(); 

Тогда вы можете просто заменить все теги с регулярным выражением или простой строки замены (удалить все между кронштейнами <>). Возможно, у XML Linq также есть готовый инструмент для этого, но я не знаю.