ここでは、正規表現とAND、OR、および大括弧で必要なすべてのテストを行います。これは演算子AND
とOR
と括弧(
と)
しかサポートしておらず、入力がいくらか整形されることを期待しています(正規表現にはスペースを入れてはいけません)。解析は改善され、アイデアは変わりません。ここで
は、全体的なテストである:ここでは
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);
}
}
この種の問題には、動的表現ツリーを使用できる場合があります。 http://msdn.microsoft.com/en-us/library/bb882637.aspx –
これらは常にこの順序で使用されますか1234 –
いいえ、任意の順序で指定できます。したがって(1または3)と(2または4)が有効です。 – jkruer01