2

内部に含まれる関数の単純な言語 (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を使用しています。

4

1 に答える 1

4

これは、.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);
      }
    }
  }
}

出力:

日付(年(5豪ドル)、月(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);
于 2010-10-27T03:00:01.383 に答える