解释器模式(Interpreter Pattern)
提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。
.情景:将 string input = "(12+5)-(12+1)";进行解析,并计算出结果。
第一眼看到这个问题瞬间蒙蔽。能直接计算为啥还要整成字符串?
将结构拆解成为了 (I+I)-(I+I) I表示数字
于是我们有了这样的结构:
public class Token { public enum Type { Interger,Plus,Minus,Lparen,Rparen } public Type MyTpye; public string Text; public Token(Type myTpye, string text) { MyTpye = myTpye; Text = text; } public override string ToString() { return $"`{Text}`"; } } class Program { static List<Token> ExpreesitionToken(string input) { List<Token> tokens = new List<Token>(); for (int i = 0; i < input.Length; i++) { switch (input[i]) { case '+': tokens.Add(new Token(Token.Type.Plus, input[i].ToString())); break; case '-': tokens.Add(new Token(Token.Type.Minus, input[i].ToString())); break; case '(': tokens.Add(new Token(Token.Type.Lparen, input[i].ToString())); break; case ')': tokens.Add(new Token(Token.Type.Rparen, input[i].ToString())); break; default: StringBuilder sb = new StringBuilder(input[i].ToString()); for (int j = i+1; j < input.Length; j++) { if (char.IsDigit(input[j])) { sb.Append(input[j]); i=j; } else { tokens.Add(new Token(Token.Type.Interger, sb.ToString())); break; } } break; } } return tokens; } static void Main(string[] args) { string input = "(12+5)-(12+1)"; ExpreesitionToken(input).ForEach(t => Console.WriteLine(t)); } }
输出看看:
接下来就是重点了,如何进行解析?
我们把表达式在拆解一个 就是 (A+A)-(B+B)=>A-B 其实就是把(括号)内的当成一个整体。 就 LeftElement Operation RightElement
public interface IElement { int Value { get;} } public class Integer : IElement { public Integer(int value) { Value = value; } public int Value { get; } } public class BinaryOperation : IElement { public enum Type { Additon,Subtraction } public Type type; public IElement Left; public IElement Right; public int Value { get { switch (type) { case Type.Additon: return Left.Value + Right.Value; break; case Type.Subtraction: return Left.Value - Right.Value; break; default: throw new AggregateException(); } } } }
最后传入数据项,返回一个操作:
static IElement Parse(IReadOnlyList<Token> tokens) { var result = new BinaryOperation(); bool haveLHS = false; for (int i = 0; i < tokens.Count; i++) { var token = tokens[i]; switch (token.MyTpye) { case Token.Type.Interger: var integer = new Integer(int.Parse(token.Text)); if (!haveLHS) { result.Left = integer; haveLHS = true; } else { result.Right = integer; } break; case Token.Type.Plus: result.type = BinaryOperation.Type.Additon; break; case Token.Type.Minus: result.type = BinaryOperation.Type.Subtraction; break; case Token.Type.Lparen: int j = i; for (; j < tokens.Count; j++) if (tokens[j].MyTpye == Token.Type.Rparen) break; var subExperssion = tokens.Skip(i + 1).Take(j - i - 1).ToList(); var element= Parse(subExperssion); if (!haveLHS) { result.Left = element; haveLHS = true; } else { result.Right = element; } i = j; break; default: throw new ArgumentOutOfRangeException(); } } return result; }
完整代码:
public interface IElement { int Value { get;} } public class Integer : IElement { public Integer(int value) { Value = value; } public int Value { get; } } public class BinaryOperation : IElement { public enum Type { Additon,Subtraction } public Type type; public IElement Left; public IElement Right; public int Value { get { switch (type) { case Type.Additon: return Left.Value + Right.Value; break; case Type.Subtraction: return Left.Value - Right.Value; break; default: throw new AggregateException(); } } } } public class Token { public enum Type { Interger, Plus, Minus, Lparen, Rparen } public Type MyTpye; public string Text; public Token(Type myTpye, string text) { MyTpye = myTpye; Text = text; } public override string ToString() { return $"`{Text}`"; } } class Program { static List<Token> ExpreesitionToken(string input) { List<Token> tokens = new List<Token>(); for (int i = 0; i < input.Length; i++) { switch (input[i]) { case '+': tokens.Add(new Token(Token.Type.Plus, input[i].ToString())); break; case '-': tokens.Add(new Token(Token.Type.Minus, input[i].ToString())); break; case '(': tokens.Add(new Token(Token.Type.Lparen, input[i].ToString())); break; case ')': tokens.Add(new Token(Token.Type.Rparen, input[i].ToString())); break; default: StringBuilder sb = new StringBuilder(input[i].ToString()); for (int j = i + 1; j < input.Length; j++) { if (char.IsDigit(input[j])) { sb.Append(input[j]); i = j; } else { tokens.Add(new Token(Token.Type.Interger, sb.ToString())); break; } } break; } } return tokens; } static IElement Parse(IReadOnlyList<Token> tokens) { var result = new BinaryOperation(); bool haveLHS = false; for (int i = 0; i < tokens.Count; i++) { var token = tokens[i]; switch (token.MyTpye) { case Token.Type.Interger: var integer = new Integer(int.Parse(token.Text)); if (!haveLHS) { result.Left = integer; haveLHS = true; } else { result.Right = integer; } break; case Token.Type.Plus: result.type = BinaryOperation.Type.Additon; break; case Token.Type.Minus: result.type = BinaryOperation.Type.Subtraction; break; case Token.Type.Lparen: int j = i; for (; j < tokens.Count; j++) if (tokens[j].MyTpye == Token.Type.Rparen) break; var subExperssion = tokens.Skip(i + 1).Take(j - i - 1).ToList(); var element= Parse(subExperssion); if (!haveLHS) { result.Left = element; haveLHS = true; } else { result.Right = element; } i = j; break; default: throw new ArgumentOutOfRangeException(); } } return result; } static void Main(string[] args) { string input = "(12+5)-(12+1)"; var tokens = ExpreesitionToken(input); var parsed = Parse(tokens); Console.WriteLine($"{input}={parsed.Value}"); } }
查看结果:
.........