Регулярное выражение для анализа функций с произвольной глубиной - PullRequest
1 голос
/ 27 октября 2010

Я разбираю простой язык (формулы Excel) для функций, содержащихся в нем.Имя функции должно начинаться с любой буквы, за которой следует любое количество букв / цифр, и заканчиваться открытым паренем (без пробелов между ними).Например MyFunc(.Функция может содержать любые аргументы, включая другие функции, и должна заканчиваться паренем ).Разумеется, математика в скобках допускается =MyFunc((1+1)), и (1+1) не следует обнаруживать как функцию, поскольку она не соответствует правилу функции, которое я только что описал.Моя цель - распознавать вызовы функций самого высокого уровня в формуле, определять имя функции, извлекать аргументы.С помощью аргументов я могу рекурсивно искать другие вызовы функций.

Используя это учебное пособие Я взломал следующие регулярные выражения.Никто, кажется, не делает трюк.Они оба терпят неудачу в тестовом примере, вставленном ниже.

Это должно работать, но полностью терпит неудачу:

(?<name>[a-z][a-z0-9]*\()(?<body>(?>[a-z][a-z0-9]*\((?<DEPTH>)|\)(?<-DEPTH>)|.?)*(?(DEPTH)(?!)))\)

Это работает для многих тестовых случаев, но не работает для тестового примера ниже,Я не думаю, что он правильно обрабатывает вложенные функции - он просто ищет открытых / закрытых парней во вложении:

(?<name>[a-z][a-z0-9]*\()(?<body>(?>\((?<DEPTH>)|\)(?<-DEPTH>)|.?)*(?(DEPTH)(?!)))\)

Вот тест, который разбивает их все:

=Date(Year(A$5),Month(A$5),1)-(Weekday(Date(Year(A$5),Month(A$5),1))-1)+{0;1;2;3;4;5}*7+{1,2,3,4,5,6,7}-1

Это должно соответствовать:

Date(ARGUMENTS1)
Weekday(ARGUMENTS2)
Where ARGUMENTS2 = Date(Year(A$5),Month(A$5),1)

Вместо этого оно соответствует:

ARGUMENTS2 = Date(Year(A$5),Month(A$5),1)-1)

Я использую .net RegEx, который обеспечивает внешнюю память.

Ответы [ 2 ]

4 голосов
/ 27 октября 2010

Это вполне соответствует возможностям регулярных выражений .NET.Вот рабочая демонстрация:

using System;
using System.Text.RegularExpressions;

namespace Test
{
  class Test
  {
    public static void Main()
    {
      Regex r = new Regex(@"
        (?<name>[a-z][a-z0-9]*\()
          (?<body>
            (?>
               \((?<DEPTH>)
             |
               \)(?<-DEPTH>)
             |
               [^()]+
            )*
            (?(DEPTH)(?!))
          )
        \)", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);

      string formula = @"=Date(Year(A$5),Month(A$5),1)-(Weekday(Date(Year((A$5+1)),Month(A$5),1))-1)+{0;1;2;3;4;5}*7+{1,2,3,4,5,6,7}-1";

      foreach (Match m in r.Matches(formula))
      {
        Console.WriteLine("{0}\n", m.Value);
      }
    }
  }
}

output:

Date(Year(A$5),Month(A$5),1)

Weekday(Date(Year((A$5+1)),Month(A$5),1))

Основная проблема с вашим регулярным выражением состояла в том, что вы включали имя функции как часть рекурсивного соответствия - например:

Name1(...Name2(...)...)

Любое открытое имя, которому не предшествовало имя, не учитывалось, поскольку оно соответствовало последней альтернативе, |.?), и это сбрасывало баланс с близкими паренами.Это также означало, что вы не могли подобрать формулы, подобные =MyFunc((1+1)), которые вы упомянули в тексте, но не включили в пример.(Я добавил дополнительный набор паренов для демонстрации.)

РЕДАКТИРОВАТЬ: Вот версия с поддержкой незначительных, цитируемых в кавычках парней:

  Regex r = new Regex(@"
    (?<name>[a-z][a-z0-9]*\()
      (?<body>
        (?>
           \((?<DEPTH>)
         |
           \)(?<-DEPTH>)
         |
           ""[^""]+""
         |
           [^()""]+
        )*
        (?(DEPTH)(?!))
      )
    \)", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
0 голосов
/ 27 октября 2010

Возможно, вы захотите посмотреть по этой ссылке: http://www.xtremevbtalk.com/archive/index.php/t-177848.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...