解释器模式 字符串解析

解释器模式(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}");

        }
    }

 

查看结果:

 

 

 

 

 .........

 

 

posted @ 2022-05-27 16:07  后跳  阅读(41)  评论(0编辑  收藏  举报