128 lines
4.4 KiB
C#
128 lines
4.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
using NCalc;
|
|
|
|
namespace Common.Tools
|
|
{
|
|
public class ExpressionEvaluator
|
|
{
|
|
public static bool EvaluateExpression(string expression, Dictionary<string, object>? variables = null)
|
|
{
|
|
try
|
|
{
|
|
// 预处理:替换中文变量名为英文别名
|
|
var (processedExpression, processedVariables) = PreprocessExpression(expression, variables);
|
|
|
|
var expr = new Expression(processedExpression, EvaluateOptions.IgnoreCase);
|
|
|
|
if (processedVariables != null)
|
|
{
|
|
foreach (var kvp in processedVariables)
|
|
{
|
|
expr.Parameters[kvp.Key] = NormalizeValue(kvp.Value);
|
|
}
|
|
}
|
|
|
|
if (expr.HasErrors())
|
|
{
|
|
throw new ArgumentException($"条件表达式格式错误: {expr.Error}");
|
|
}
|
|
|
|
var result = expr.Evaluate();
|
|
return Convert.ToBoolean(result);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new ArgumentException($"条件表达式异常: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private static (string, Dictionary<string, object>) PreprocessExpression(
|
|
string expression,
|
|
Dictionary<string, object>? variables)
|
|
{
|
|
if (variables == null || variables.Count == 0)
|
|
return (expression, variables ?? new Dictionary<string, object>());
|
|
|
|
// 生成变量名映射 (中文 -> 英文别名)
|
|
var chineseToAlias = new Dictionary<string, string>();
|
|
var aliasToValue = new Dictionary<string, object>();
|
|
int counter = 1;
|
|
|
|
foreach (var key in variables.Keys)
|
|
{
|
|
if (ContainsChinese(key))
|
|
{
|
|
string alias = $"var_{counter}";
|
|
counter++;
|
|
chineseToAlias[key] = alias;
|
|
aliasToValue[alias] = variables[key];
|
|
}
|
|
}
|
|
|
|
// 如果没有中文变量名,直接返回原始数据
|
|
if (chineseToAlias.Count == 0)
|
|
return (expression, variables);
|
|
|
|
// 替换表达式中的中文变量名
|
|
string processedExpression = expression;
|
|
foreach (var pair in chineseToAlias)
|
|
{
|
|
// 使用正则确保完整匹配变量名
|
|
string pattern = $@"\b{Regex.Escape(pair.Key)}\b";
|
|
processedExpression = Regex.Replace(
|
|
processedExpression,
|
|
pattern,
|
|
pair.Value,
|
|
RegexOptions.Compiled
|
|
);
|
|
}
|
|
|
|
// 创建新变量字典(英文别名 + 原始英文变量)
|
|
var newVariables = new Dictionary<string, object>(aliasToValue);
|
|
foreach (var key in variables.Keys)
|
|
{
|
|
if (!ContainsChinese(key))
|
|
{
|
|
newVariables[key] = variables[key];
|
|
}
|
|
}
|
|
|
|
return (processedExpression, newVariables);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 归一化变量取值:输入变量的值常以字符串形式保存(如 "10"),
|
|
/// 若直接参与比较,NCalc 会按字符串逐位比较("10" > "5" 为假),
|
|
/// 导致大于/小于判断失真。此处将可解析为数字/布尔的字符串转换为对应类型,
|
|
/// 使比较按数值语义进行;无法解析的字符串保持原样。
|
|
/// </summary>
|
|
private static object? NormalizeValue(object? value)
|
|
{
|
|
if (value is string s)
|
|
{
|
|
if (double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var d)
|
|
|| double.TryParse(s, out d))
|
|
{
|
|
return d;
|
|
}
|
|
if (bool.TryParse(s, out var b))
|
|
{
|
|
return b;
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
// 检查字符串是否包含中文字符
|
|
private static bool ContainsChinese(string text)
|
|
{
|
|
return text.Any(c => c >= 0x4E00 && c <= 0x9FFF);
|
|
}
|
|
}
|
|
} |