解析逻辑字符串并动态替换值:"[field]>3&&[field2]<78". field、field2为动态替换值
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
public class ExpressionParser
{
#region Fields
/// <summary>
/// 将表达式以&&或者||切割
/// group[1]和group[3]为单个逻辑表达式 group[2]为右边的运算符【&&或||】
/// </summary>
private static readonly Regex regCutItem = new Regex(@"(.*?)([&||]{2})|(S.*)");
/// <summary>
/// 将每个单独的item匹配出小分子 例子:3>2 => [3,>,2]
/// </summary>
private static readonly Regex regCutMolecule = new Regex(@"(.*?)([>|<]=?|=)(.*)");
/// <summary>
/// 验证每个单独的item是否合法
/// </summary>
private static readonly Regex regValidMolecult = new Regex(@"^([w[]]*?)([>|<]=?|=)([w[]]*)$");
/// <summary>
/// 提取表达式中的小括号内容 (如有小括号嵌套 需重复匹配;最先获取最内部括号内容,由内向外获取)
/// </summary>
private static readonly Regex regSmallBracket = new Regex(@"([^(]*?)");
/// <summary>
/// 提取单个单个小分子的字段值
/// </summary>
private static readonly Regex regGetField = new Regex(@"^s*?[(S+)]s*?$");
private static readonly string trueText = "1=1";
private static readonly string falseText = "1=2";
#endregion
#region Methods
/// <summary>
/// 判断表达式的有效性
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
public static bool JudgeValid(string expression)
{
if (string.IsNullOrEmpty(expression)) new ArgumentException("is null or empty", "expression");
bool haveBracketite = regSmallBracket.IsMatch(expression);
//匹配出所有括号内的内容验证是否合法,合法则remove掉
while (regSmallBracket.IsMatch(expression))
{
MatchCollection collection = regSmallBracket.Matches(expression);
foreach (Match bracketite in collection)
{
int index = 0; string opL = string.Empty, opR = string.Empty;
//匹配到的值 带括号(8>5&&7>3.....)
string expBracketite = bracketite.Value;
index = expression.IndexOf(expBracketite);
//括号内容前的连接运算符
if (index >= 2) opL = expression.Substring(index - 2, 2);
//括号内容后的连接运算符
if (expression.Length > index + expBracketite.Length + 2) opR = expression.Substring(index + expBracketite.Length, 2);
//如果连接符不为&&或||则不符合表达式规则
if (!string.IsNullOrEmpty(opL) && opL != "&&" && opL != "||") return false;
if (!string.IsNullOrEmpty(opR) && opR != "&&" && opR != "||") return false;
MatchCollection items = regCutItem.Matches(expBracketite.Substring(1, expBracketite.Length - 2));
//如果集合数小于1 则括号之间内容为空或者内容不符合规则
if (items.Count < 1) return false;
int indexOfItem1 = 0;
foreach (Match item in items)
{
indexOfItem1++;
//获取表达式
string expItem = indexOfItem1 == items.Count ? item.Groups[3].Value : item.Groups[1].Value;
//验证表达式的有效性
if (!regValidMolecult.IsMatch(expItem)) return false;
}
//remove括号内的表达式以及括号前的连接运算符
expression = expression.Remove(index < 2 ? index : index - 2, expBracketite.Length + (index < 2 ? index : 2));
}
}
//验证去除括号内容后剩下表达式的有效性
MatchCollection expItems = regCutItem.Matches(expression);
//如果表达式没有括号且匹配结果数小于1 则表达式内容不符合规则
if (!haveBracketite && expItems.Count < 1) return false;
int indexOfItem = 0;
foreach (Match item in expItems)
{
indexOfItem++;
//获取表达式
string expItem = indexOfItem == expItems.Count ? item.Groups[3].Value : item.Groups[1].Value;
//验证表达式的有效性
if (!regValidMolecult.IsMatch(expItem)) return false;
}
return true;
}
/// <summary>
/// 获取表达式结果
/// </summary>
/// <param name="expression">表达式</param>
/// <param name="prm"></param>
/// <returns></returns>
public static bool GetResult(string expression, Dictionary<string, object> prm)
{
if (!JudgeValid(expression)) throw new Exception("invalid expression");
//匹配出所有括号内的内容计算结果并根据结果替换对应的值
while (regSmallBracket.IsMatch(expression))
{
MatchCollection collection = regSmallBracket.Matches(expression);
foreach (Match bracketite in collection)
{
//表达式内容赋值
string expBracketite = bracketite.Value;
int index = expression.IndexOf(expBracketite);
//获取表达式计算后的结果
bool result = MosaicLambda(expBracketite.Substring(1, expBracketite.Length - 2), prm);
//根据结果将括号内表达式替换成不同字符串
expression = expression.Remove(index, expBracketite.Length).Insert(index, result ? trueText : falseText);
}
}
return MosaicLambda(expression, prm);
}
/// <summary>
/// 获取表达式结果
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
static bool GetResult(string expression)
{
return GetResult(expression, new Dictionary<string, object>());
}
/// <summary>
/// 拼接动态Lambda并获取结果
/// </summary>
/// <param name="expression"></param>
/// <param name="prm"></param>
/// <returns></returns>
static bool MosaicLambda(string expression, Dictionary<string, object> prm)
{
//Fields
Expression lambda = null;
string connector = null;
MatchCollection items = regCutItem.Matches(expression);
int indexOfItem = 0;
foreach (Match item in items)
{
indexOfItem++;
Expression left = null, right = null;
BinaryExpression binary = null;
//获取表达式
string expItem = indexOfItem == items.Count ? item.Groups[3].Value : item.Groups[1].Value;
Match Molecule = regCutMolecule.Matches(expItem)[0];
//判断左边是否是字段
if (regGetField.IsMatch(Molecule.Groups[1].Value))
{
string field = regGetField.Matches(Molecule.Groups[1].Value)[0].Groups[1].Value;
if (!prm.ContainsKey(field)) throw new Exception($"未提供必须字段[{field}]");
left = Expression.Constant(prm[field]);
}
else
{
object v = null;
Type t = TryGetType(Molecule.Groups[1].Value, out v);
left = Expression.Constant(v, t);
}
//判断右边是否是字段
if (regGetField.IsMatch(Molecule.Groups[3].Value))
{
string field = regGetField.Matches(Molecule.Groups[3].Value)[0].Groups[1].Value;
if (!prm.ContainsKey(field)) throw new Exception($"未提供必须字段[{field}]");
right = Expression.Constant(prm[field]);
}
else
{
object v = null;
Type t = TryGetType(Molecule.Groups[3].Value, out v);
right = Expression.Constant(v, t);
}
if (left.Type != right.Type) throw new Exception("尝试比较两个不同数据类型的值");
//根据操作符选择合适的方法进行装载
switch (Molecule.Groups[2].Value)
{
case ">":
binary = Expression.GreaterThan(left, right);
break;
case ">=":
binary = Expression.GreaterThanOrEqual(left, right);
break;
case "=":
binary = Expression.Equal(left, right);
break;
case "<=":
binary = Expression.LessThanOrEqual(left, right);
break;
case "<":
binary = Expression.LessThan(left, right);
break;
default: throw new Exception("invalid charactor");
}
//根据上一个item设置的连接符进行相应的操作
if (connector == null) lambda = binary;
else
{
switch (connector)
{
case "&&":
lambda = Expression.And(lambda, binary);
break;
case "||":
lambda = Expression.Or(lambda, binary);
break;
default: throw new Exception("invalid charactor");
}
}
//And|Or赋值
connector = item.Groups[2].Value;
}
return Expression.Lambda<Func<bool>>(lambda).Compile().Invoke();
}
static Type TryGetType(string v, out object obj)
{
int i = default(int); float f = default(float); double d = default(double);
if (int.TryParse(v, out i)) { obj = i; return typeof(int); }
if (float.TryParse(v, out f)) { obj = f; return typeof(float); }
if (double.TryParse(v, out d)) { obj = d; return typeof(double); }
obj = v;
return typeof(string);
}
#endregion
}
}