2

ユーザーが正規表現を使用してデータにフィルターを作成できる C# プロジェクトがあります。フィルタはいくつでも追加できます。各フィルターは、フィールドと、ユーザーが入力する正規表現で構成されます。

現在、すべての AND ロジックで動作します。各フィルターをループし、一致しない場合は、skip = true を設定してループから抜け出します。次に、skip == true の場合、そのレコードをスキップして含めません。そのため、フィールドを含めるには、すべてのフィルターが一致する必要があります。

しかし、今では、より複雑なロジック ルールを追加する機能が求められています。たとえば、4 つのフィルタ ルールを作成したとします。1 AND 2 AND (3 OR 4) または 1 OR 2 OR 3 OR 4 を指定したい場合や、(1 AND 2 AND 3) OR 4 などを指定したい場合があります。 .要点がわかると思います。

必要なロジックを入力できるテキスト ボックスを追加しました。

私は頭を悩ませてきましたが、これを機能させる方法に困惑しています。私の唯一の結論は、テキストボックスに入力したテキストに基づいて動的な IF ステートメントを作成できるようにすることですが、それが可能かどうかはわかりません。

これを行う簡単な方法があるはずですが、わかりません。誰かが私を助けることができれば、本当に感謝しています。

ありがとう!

4

5 に答える 5

4

これは、正規表現と AND、OR、および括弧を使用して、必要に応じて機能する完全なテストです。これは演算子ANDandORおよびかっこ(and and のみをサポートすることに注意してください)。解析は改善できますが、考え方は変わりません。

全体的なテストは次のとおりです。

var input = ".* AND [0-9]+ AND abc OR (abc AND def)";
var rpn = ParseRPN(input);  
var test = GetExpression(new Queue<string>(rpn.Reverse())).Compile();
test("abc");    // false
test("abc0");   // true
test("abcdef"); // true

逆ポーランド記法への解析は次のとおりです。

public Queue<string> ParseRPN(string input)
{
    // improve the parsing into tokens here
    var output = new Queue<string>();
    var ops = new Stack<string>();
    input = input.Replace("(","( ").Replace(")"," )");
    var split = input.Split(' ');

    foreach (var token in split)
    {
        if (token == "AND" || token == "OR")
        {
            while (ops.Count > 0 && (ops.Peek() == "AND" || ops.Peek() == "OR"))
            {
                output.Enqueue(ops.Pop());
            }
            ops.Push(token);
        }
        else if (token == "(") ops.Push(token);
        else if (token == ")")
        {
            while (ops.Count > 0 && ops.Peek() != "(")
            {
                output.Enqueue(ops.Pop());
            }
            ops.Pop();
        }
        else output.Enqueue(token); // it's a number        
    }

    while (ops.Count > 0)
    {
        output.Enqueue(ops.Pop());
    }

    return output;
}

そして魔法GetExpression

public Expression<Func<string,bool>> GetExpression(Queue<string> input)
{
    var exp = input.Dequeue();
    if (exp == "AND") return GetExpression(input).And(GetExpression(input));
    else if (exp == "OR") return GetExpression(input).Or(GetExpression(input));
    else return (test => Regex.IsMatch(test, exp));
}

これは に依存していることに注意してくださいPredicateBuilder。ただし、使用される拡張関数はここにあります。

public static class PredicateBuilder
{
  public static Expression<Func<T, bool>> True<T> ()  { return f => true;  }
  public static Expression<Func<T, bool>> False<T> () { return f => false; }

  public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
                                                      Expression<Func<T, bool>> expr2)
  {
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
    return Expression.Lambda<Func<T, bool>>
          (Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
  }

  public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
                                                       Expression<Func<T, bool>> expr2)
  {
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
    return Expression.Lambda<Func<T, bool>>
          (Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
  }
}
于 2012-05-01T02:37:53.663 に答える
1

次のようなもの - 二項演算を表す演算クラスを定義し、ツリーを構築します。

interface IFilter  
{
 bool Filter(Record r);
}

class SimpleFilter : IFilter
{ 
 bool Filter(Record r)
 {
  return RegExpMatch(r); 
 }
}

class AndFilter : IFilter
{ 
 public AndFilter(IFilter left, IFilter right) {}

 bool Filter(Record r)
 {
  return left.Filter(r) && right.Filter(r); 
 }
}

class OrFilter : IFilter
{ 
 public OrFilter(IFilter left, IFilter right) {}

 bool Filter(Record r)
 {
  return left.Filter(r) || right.Filter(r); 
 }
}
于 2012-05-01T01:54:10.323 に答える
0

最初のステップは、式を抽象構文ツリーに解析することです。これを行うには、分流場アルゴリズムを使用できます。

それを行った後、仮想メソッドまたはインターフェイスを使用して、ツリーを再帰的に評価できます。たとえばSimpleNode、単純な式(例のように)を表し、1それを評価できるクラスを持つことができます。次に、操作AndNodeを表しAND、2 つの子ノードがあります。子ノードを評価し、両方が成功したかどうかを返します。

于 2012-05-01T01:58:11.040 に答える
0

この仕様パターンの説明 (コード例付き) が役立ちます。

http://en.wikipedia.org/wiki/Specification_pattern#C.23

于 2012-05-01T02:00:05.427 に答える