这是一个完整的测试,可以根据需要使用正则表达式和 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);
}
}