c# 解释器模式与sping.net表达式的结合应用(金融里经常需要用到公式,这个公式是抽象的需要自己解释)
1.代码 using Spring.Expressions; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace ConsoleApplication49 { public interface IExpressionContext { /// <summary> /// 什么是终结符单词 客户端自己要给出 /// </summary> Dictionary<string, string> map { get; set; } string GetValueByKey(string key); } public class ExpressionContext : IExpressionContext { public Dictionary<string, string> map { get; set; } public string GetValueByKey(string key) { if (map.ContainsKey(key)) return map[key]; return key; } } public abstract class Expression { /// <summary> /// 终结符 /// </summary> private string key; public string Key { get { return key; } set { key = value; } } //解析公式和数值,其中var中的key值是是公式中的参数,value值是具体的数字 //这里字典可以抽象为上下文 ctx,此处自己扩展 public abstract string interpreter(IExpressionContext ctx); } public class VarExpression : Expression { public VarExpression(string _key) { this.Key = _key; } //从map中取之 public override string interpreter(IExpressionContext ctx) { if (ctx.map.ContainsKey(Key)) return ctx.GetValueByKey(Key); else if (Key.IndexOf('(') >= 0) { var key1 = Key.Split('(')[1]; return "(" + ctx.GetValueByKey(key1); } else if (Key.IndexOf(')') >= 0) { var key1 = Key.Split(')')[0]; return ctx.GetValueByKey(key1) + ")"; } return Key; } } public abstract class SymbolExpression : Expression { protected Expression left; protected Expression right; //所有的解析公式都应只关心自己左右两个表达式的结果 public SymbolExpression(Expression _left, Expression _right) { this.left = _left; this.right = _right; } } public class AddExpression : SymbolExpression { public AddExpression(Expression _left, Expression _right) : base(_left, _right) { } //把左右两个表达式运算的结果加起来 public override string interpreter(IExpressionContext ctx) { return (base.left.interpreter(ctx)) + "+" + (base.right.interpreter(ctx)); } } public class SubExpression : SymbolExpression { public SubExpression(Expression _left, Expression _right) : base(_left, _right) { } //左右两个表达式相减 public override string interpreter(IExpressionContext ctx) { return base.left.interpreter(ctx) + "-" + base.right.interpreter(ctx); } } public class MultExpression : SymbolExpression { public MultExpression(Expression _left, Expression _right) : base(_left, _right) { } //左右两个表达式相减 public override string interpreter(IExpressionContext ctx) { return base.left.interpreter(ctx) + "*" + base.right.interpreter(ctx); } } public class Dividexpression : SymbolExpression { public Dividexpression(Expression _left, Expression _right) : base(_left, _right) { } //左右两个表达式相减 public override string interpreter(IExpressionContext ctx) { return base.left.interpreter(ctx) + "/" + base.right.interpreter(ctx); } } public class PExpression : SymbolExpression { public PExpression(Expression _left, Expression _right) : base(_left, _right) { } //左右两个表达式相减 public override string interpreter(IExpressionContext ctx) { return base.left.interpreter(ctx) + "^" + base.right.interpreter(ctx); } } public class Calculator { //定义的表达式 private Expression expression; //构造函数传参,并解析 public Calculator(string exprStr) { //定义一个堆栈,安排运算的先后顺序 Stack<Expression> stack = new Stack<Expression>(); string[] sb = { "+", "-", "*", "/", "^" }; List<string> items = new List<string>(); string word = string.Empty; char[] chs = exprStr.ToCharArray(); List<string> chsdict = new List<string>(); foreach (var item in chs) { chsdict.Add(item.ToString()); } foreach (string ch in chsdict) { if (!sb.Contains(ch.ToString())) { word += ch.ToString(); //if (exprStr.IndexOf(ch) == exprStr.ToCharArray().Length - 1) if (object.ReferenceEquals(ch, chsdict[chsdict.Count - 1])) { items.Add(word); } } else { items.Add(word.Clone().ToString()); items.Add(ch.ToString()); word = string.Empty; } } int cx = 0; //表达式拆分为字符数组 char[] charArray = exprStr.ToCharArray(); //运算 Expression left = null; Expression right = null; for (int i = 0; i < items.Count; i++) { if (cx >= items.Count) { break; } word = items[cx++]; switch (word) { case "+": //加法 //加法结果放到堆栈中 left = stack.Peek(); right = new VarExpression(items[cx++]); stack.Push(new AddExpression(left, right)); break; case "-": left = stack.Peek(); right = new VarExpression(items[cx++]); stack.Push(new SubExpression(left, right)); break; case "^": left = stack.Peek(); right = new VarExpression(items[cx++]); stack.Push(new PExpression(left, right)); break; case "/": left = stack.Peek(); right = new VarExpression(items[cx++]); stack.Push(new Dividexpression(left, right)); break; case "*": left = stack.Peek(); right = new VarExpression(items[cx++]); stack.Push(new MultExpression(left, right)); break; default: //公式中的变量 stack.Push(new VarExpression(word)); break; } } //把运算结果抛出来 this.expression = stack.Peek(); } //开始运算 public string run(IExpressionContext ctx) { return this.expression.interpreter(ctx); } } public class Client { //运行四则运算 public static void Main(string[] args) { while (true) { string exp = string.Empty; string expStr = getExpStr(); //赋值 得到终结符单词 Dictionary<string, string> maps = getValue(expStr); Calculator cal = new Calculator(expStr); IExpressionContext ctx = new ExpressionContext(); ctx.map = maps; exp = cal.run(ctx); var val = ExpressionEvaluator.GetValue(null, exp); Console.WriteLine("运算结果为:" + expStr + "=" + exp + "=" + val.ToString()); } Console.ReadKey(); } //获得表达式 public static String getExpStr() { Console.WriteLine("请输入表达式:"); return Console.ReadLine(); } //获得值映射 什么才是终结符单词客户端要自己给出定义 public static Dictionary<string, string> getValue(string exprStr) { exprStr = exprStr.Replace("(", "").Replace(")", ""); //定义非终结符 string[] sb = { "+", "-", "*", "/", "^" }; string copyExpStr = exprStr.Clone().ToString(); foreach (char ch in exprStr.ToCharArray()) { if (sb.Contains(ch.ToString())) { copyExpStr = copyExpStr.Replace(ch.ToString(), ","); } } var items = copyExpStr.Split(','); Dictionary<string, string> map = new Dictionary<string, string>(); //解析有几个参数要传递 foreach (string ch in items) { if (!sb.Contains(ch.ToString()) && !Regex.IsMatch(ch, @"[0-9]+(.d+)?") && ch != "(" && ch != ")") { //解决重复参数的问题 if (!map.ContainsKey(ch.ToString())) { Console.WriteLine("请输入" + ch + "的值:"); string in1 = Console.ReadLine(); map.Add(ch.ToString(), in1); } } } return map; } } }
2.客户端测试