原 状态机 搜索字符串中的特定占位符

问题:xz[[cenvENVzxcENV[      fffff  ]dsbgENV[fecccccc]nqe  W3]NBENV[]ZXC   这个字符串中总共有三个变量区,规定ENV[]  方括号中间包含的即是变量,那么使用的过程中需要找到这个变量在替换。

使用状态机首先需要定义系统的状态的个数及状态之间的转换过程及条件

本例中总共定义了6种状态 common char:普通字符串 env:变量内容 over:状态机终止(字符串超长)  maybe:可能属于变量 maybeOver:后面紧跟着的可能是变量 envOver:变量终止。

状态直接的转换关系如图

那么示例字符串(xz[[cenvENVzxcENV[      fffff  ]dsbgENV[fecccccc]nqe  W3]NBENV[]ZXC)的分解应当如下图:

代码: 状态机定义:

  public delegate Tuple<bool, T> HandleType<T>(IState<T> current, IState<T> previous, T originData, int currentIndex);

    public interface IState<T>
    {
        string Name { get; set; }
        string Value { get; set; }

        //后一个状态u
        IList<IState<T>> Nexts { get; set; }
        //判断状态如何迁移
        Func<IState<T>, T, int, IState<T>> Selector { get; set; }

    }
    public interface IContext<T> : IEnumerator<T>, IEnumerable<T>
    {
        /// <summary>
        /// 初始值
        /// </summary>
        T OriginData { get; set; }
        /// <summary>
        /// 用于在状态机变化过程中自定义写处理方法
        /// </summary>
        IDictionary<Tuple<IState<T>, IState<T>>, HandleType<T>> Handles { get; set; }
        /// <summary>
        /// 当前状态
        /// </summary>
        IState<T> CurrentState { get; set; }
        /// <summary>
        /// 前件处理 
        /// </summary>
        /// <param name="next"></param>
        /// <returns></returns>
        bool transition(IState<T> next);
    }

    public class State : IState<string>
    {
        /// <summary>
        /// 状态类型
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 用于保存本次状态过程的值
        /// </summary>
        public string Value { get; set; }
        IList<IState<string>> IState<string>.Nexts { get; set; }
        public Func<IState<string>, string, int, IState<string>> Selector { get; set; }
    }

    /// <summary>
    /// 定义的状态机
    /// </summary>
    public class Context<T> : IContext<T>
    {
        public Context()
        {
            Handles = new Dictionary<Tuple<IState<T>, IState<T>>, HandleType<T>>();
        }
        public T OriginData { get; set; }
        private int originDataIndex { get; set; }
        T currentData;
        public IDictionary<Tuple<IState<T>, IState<T>>, HandleType<T>> Handles { get; set; }
        public IState<T> CurrentState { get; set; }
        T IEnumerator<T>.Current { get { return currentData; } }
        object IEnumerator.Current { get { return currentData; } }
        bool IContext<T>.transition(IState<T> next)
        {
            IContext<T> context = this as IContext<T>;
            if (context.CurrentState == null || context.CurrentState.Nexts.Contains(next))
            {
                var key = Tuple.Create(context.CurrentState, next);
                if (context.Handles.ContainsKey(key) && context.Handles[key] != null)
                {
                    var result = context.Handles[key](context.CurrentState, next, OriginData, originDataIndex);
                    if (!result.Item1)
                    {
                        currentData = result.Item2;
                        return false;
                    }
                    else
                    {
                        currentData = result.Item2;
                    }
                }
                context.CurrentState = next;
                return true;
            }
            return false;
        }
        bool IEnumerator.MoveNext()
        {
            IContext<T> context = this as IContext<T>;
            IState<T> current = context.CurrentState;
            if (current == null)
                throw new Exception("必须设置初始状态");
            if (context.CurrentState.Selector != null)
            {
                IState<T> next = context.CurrentState.Selector(context.CurrentState, OriginData, originDataIndex);
                var success = context.transition(next);
                originDataIndex++;
                return success;
            }
            return false;
        }
        void IEnumerator.Reset()
        {
            originDataIndex = 0;
        }
        #region IDisposable Support
        private bool disposedValue = false; // 要检测冗余调用
        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // TODO: 释放托管状态(托管对象)。
                }
                // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                // TODO: 将大型字段设置为 null。
                disposedValue = true;
            }
        }
        void IDisposable.Dispose()
        {
            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            Dispose(true);
            // TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
            // GC.SuppressFinalize(this);
        }
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return this;
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this;
        }
        #endregion
    }

定义状态机种的状态及状态之间的转换关系

            //保存状态变化时的值及对应的状态
            var dic = new List<Tuple<string, string>>();

            //定义六种状态实例
            IState<string> common = new State() { Name = "common char" };
            IState<string> env = new State() { Name = "env" };
            IState<string> over = new State() { Name = "over" };
            IState<string> maybe = new State() { Name = "maybe" };
            IState<string> maybeOver = new State() { Name = "maybeOver" };
            IState<string> envOver = new State() { Name = "envOver" };

            //初始化状态机
            IContext<string> stringState = new Context<string> { CurrentState = common };
            stringState.OriginData = "";
            //附加处理
            HandleType<string> attachResolve = (IState<string> previous, IState<string> current, string originData, int currentIndex) =>
            {
                current.Value += originData[currentIndex];
                return new Tuple<bool, string>(true, current.Value);
            };
            //覆盖处理
            HandleType<string> setResolve = (IState<string> previous, IState<string> current, string originData, int currentIndex) =>
            {
                current.Value = originData[currentIndex].ToString();
                dic.Add(new Tuple<string, string>(previous.Name, previous.Value));
                return new Tuple<bool, string>(true, current.Value);
            };
            //over 取前一个状态的值
            HandleType<string> preResolve = (IState<string> previous, IState<string> current, string originData, int currentIndex) =>
            {
                dic.Add(new Tuple<string, string>(previous.Name, previous.Value));
                return new Tuple<bool, string>(true, previous.Value);
            };
            //common char 状态转换 及不同转换条件下处理方法
            common.Nexts = new List<IState<string>>() { common, over, maybe };
            common.Selector = (state, originData, currentIndex) =>
            {
                if (currentIndex >= originData.Length)
                {
                    return over;
                }
                var ch = originData[currentIndex];
                if (ch == 'E')
                {
                    return maybe;
                }
                return common;
            };

            stringState.Handles.Add(Tuple.Create(common, common), attachResolve);
            stringState.Handles.Add(Tuple.Create(common, over), preResolve);
            stringState.Handles.Add(Tuple.Create(common, maybe), setResolve);
            //env  状态转换 及不同转换条件下处理方法
            env.Nexts = new List<IState<string>>() { envOver, over, env };
            env.Selector = (state, originData, currentIndex) =>
            {
                if (currentIndex >= originData.Length)
                {
                    return over;
                }
                var ch = originData[currentIndex];
                if (ch == ']') return envOver; else return env;
            };

            stringState.Handles.Add(Tuple.Create(env, envOver), setResolve);
            stringState.Handles.Add(Tuple.Create(env, over), preResolve);
            stringState.Handles.Add(Tuple.Create(env, env), attachResolve);


            // maybe 状态转换 及不同转换条件下处理方法
            maybe.Nexts = new List<IState<string>>() { maybe, common, env, over, maybeOver };
            maybe.Selector = (state, originData, currentIndex) =>
            {
                if (currentIndex >= originData.Length)
                {
                    return over;
                }
                var ch = originData[currentIndex];
                if (state.Value == "E" && ch == 'N') return maybe;
                if (state.Value == "EN" && ch == 'V') return maybe;
                if (state.Value == "ENV" && ch == '[')
                {
                    return maybeOver;
                }
                return common;
            };
            stringState.Handles.Add(Tuple.Create(maybe, maybe), attachResolve);
            stringState.Handles.Add(Tuple.Create(maybe, common), setResolve);
            stringState.Handles.Add(Tuple.Create(maybe, env), setResolve);
            stringState.Handles.Add(Tuple.Create(maybe, over), preResolve);
            stringState.Handles.Add(Tuple.Create(maybe, maybeOver), setResolve);

            // maybeOver 状态转换 及不同转换条件下处理方法
            maybeOver.Nexts = new List<IState<string>>() { env, envOver, over };
            maybeOver.Selector = (state, originData, currentIndex) =>
            {
                var ch = originData[currentIndex];
                if (currentIndex >= originData.Length)
                {
                    return over;
                }
                if (ch == ']') return envOver;
                return env;
            };
            stringState.Handles.Add(Tuple.Create(maybeOver, env), setResolve);
            stringState.Handles.Add(Tuple.Create(maybeOver, over), preResolve);

            // envOver 状态转换 及不同转换条件下处理方法
            envOver.Nexts = new List<IState<string>>() { common, maybe, over };
            envOver.Selector = (state, originData, currentIndex) =>
            {
                if (currentIndex >= originData.Length)
                {
                    return over;
                }
                var ch = originData[currentIndex];
                if (ch == 'E') return maybe;
                return common;
            };
            stringState.Handles.Add(Tuple.Create(envOver, common), setResolve);
            stringState.Handles.Add(Tuple.Create(envOver, maybe), setResolve);
            stringState.Handles.Add(Tuple.Create(envOver, over), preResolve);

            // over 状态转换 及不同转换条件下处理方法
            over.Nexts = new List<IState<string>>() { };
            stringState.Handles.Add(Tuple.Create(over, maybe), preResolve);
            stringState.Handles.Add(Tuple.Create(over, common), preResolve);
            stringState.Handles.Add(Tuple.Create(over, env), preResolve);
            stringState.Handles.Add(Tuple.Create(over, envOver), preResolve);
            stringState.Handles.Add(Tuple.Create(over, maybeOver), preResolve);

测试:

             Console.WriteLine("测试字符串");
            string input = "";
            //   "xz[[cenvENVzxcENV[      fffff  ]dsbgENV[fecccccc]nqe  W3]NBENV[]ZXC"
            while (!string.IsNullOrEmpty(input = Console.ReadLine()))
            {
                stringState.OriginData = input;
                foreach (var item in stringState)
                {
                    Console.WriteLine("当前状态{0}---当前值{1}", stringState.CurrentState.Name, item);
                }
                Console.WriteLine("");
                Console.WriteLine("");
                Console.WriteLine("抽取出的Symbol");
                dic.ForEach(a =>
                {
                    Console.WriteLine("字符串类型:" + a.Item1 + "-------------分解值:" + a.Item2);
                });
            }

测试结果:

测试字符串 xz[[cenvENVzxcENV[      fffff  ]dsbgENV[fecccccc]nqe  W3]NBENV[]ZXC
当前状态common char---当前值x
当前状态common char---当前值xz
当前状态common char---当前值xz[
当前状态common char---当前值xz[[
当前状态common char---当前值xz[[c
当前状态common char---当前值xz[[ce
当前状态common char---当前值xz[[cen
当前状态common char---当前值xz[[cenv
当前状态maybe---当前值E
当前状态maybe---当前值EN
当前状态maybe---当前值ENV
当前状态common char---当前值z
当前状态common char---当前值zx
当前状态common char---当前值zxc
当前状态maybe---当前值E
当前状态maybe---当前值EN
当前状态maybe---当前值ENV
当前状态maybeOver---当前值[
当前状态env---当前值
当前状态env---当前值
当前状态env---当前值
当前状态env---当前值
当前状态env---当前值
当前状态env---当前值
当前状态env---当前值      f
当前状态env---当前值      ff
当前状态env---当前值      fff
当前状态env---当前值      ffff
当前状态env---当前值      fffff
当前状态env---当前值      fffff
当前状态env---当前值      fffff
当前状态envOver---当前值]
当前状态common char---当前值d
当前状态common char---当前值ds
当前状态common char---当前值dsb
当前状态common char---当前值dsbg
当前状态maybe---当前值E
当前状态maybe---当前值EN
当前状态maybe---当前值ENV
当前状态maybeOver---当前值[
当前状态env---当前值f
当前状态env---当前值fe
当前状态env---当前值fec
当前状态env---当前值fecc
当前状态env---当前值feccc
当前状态env---当前值fecccc
当前状态env---当前值feccccc
当前状态env---当前值fecccccc
当前状态envOver---当前值]
当前状态common char---当前值n
当前状态common char---当前值nq
当前状态common char---当前值nqe
当前状态common char---当前值nqe
当前状态common char---当前值nqe
当前状态common char---当前值nqe  W
当前状态common char---当前值nqe  W3
当前状态common char---当前值nqe  W3]
当前状态common char---当前值nqe  W3]N
当前状态common char---当前值nqe  W3]NB
当前状态maybe---当前值E
当前状态maybe---当前值EN
当前状态maybe---当前值ENV
当前状态maybeOver---当前值[
当前状态envOver---当前值[
当前状态common char---当前值Z
当前状态common char---当前值ZX
当前状态common char---当前值ZXC
当前状态over---当前值ZXC


抽取出的Symbol
字符串类型:common char-------------分解值:xz[[cenv
字符串类型:maybe-------------分解值:ENV
字符串类型:common char-------------分解值:zxc
字符串类型:maybe-------------分解值:ENV
字符串类型:maybeOver-------------分解值:[
字符串类型:env-------------分解值:      fffff
字符串类型:envOver-------------分解值:]
字符串类型:common char-------------分解值:dsbg
字符串类型:maybe-------------分解值:ENV
字符串类型:maybeOver-------------分解值:[
字符串类型:env-------------分解值:fecccccc
字符串类型:envOver-------------分解值:]
字符串类型:common char-------------分解值:nqe  W3]NB
字符串类型:maybe-------------分解值:ENV
字符串类型:envOver-------------分解值:]
字符串类型:common char-------------分解值:ZXC

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Spark生态圈

[spark] Task执行流程

在文章TaskScheduler 任务提交与调度源码解析 中介绍了Task在executor上的逻辑分配,调用TaskSchedulerImpl的resourc...

1391
来自专栏葡萄城控件技术团队

如何在保留装箱对象的前提下修改值

有人问如何在保留装箱对象的前提下修改值? 场景: object obj = 100; Console.WriteLine("original object va...

2057
来自专栏分布式系统和大数据处理

.Net中的反射(序章) - Part.1

反射是.Net提供给我们的一件强力武器,尽管大多数情况下我们不常用到反射,尽管我们可能也不需要精通它,但对反射的使用作以初步了解在日后的开发中或许会有所帮助。

994
来自专栏DOTNET

ASP.NET Web API编程——模型验证与绑定

1.模型验证 使用特性约束模型属性 可以使用System.ComponentModel.DataAnnotations提供的特性来限制模型。 例如,Requi...

8415
来自专栏听雨堂

VB中Unicode的转换

    VB本身的字符串格式就是Unicode,用Winsock发送字符串的话,会默认把字符串转换为Ansi的格式进行发送。Ansi格式,对于英文符号等仍然使用...

2258
来自专栏DOTNET

ASP.NET Web API编程——序列化与内容协商

1 多媒体格式化器 多媒体类型又叫MIME类型,指示了数据的格式。在HTTP协议中多媒体类型描述了消息体的格式。一个多媒体类型包括两个字符串:类型和子类型。 例...

3866
来自专栏菩提树下的杨过

利用xml轻松读取web.config中的用户自定义节

虽然vs.net2.0为我们提供了 ConfigurationManager.AppSettings["..."]; ConfigurationManage...

17910
来自专栏圣杰的专栏

ABP入门系列(8)——Json格式化

讲完了分页功能,这一节我们先不急着实现新的功能。来简要介绍下Abp中Json的用法。为什么要在这一节讲呢?当然是做铺垫啊,后面的系列文章会经常和Json这个东...

3049
来自专栏码农阿宇

关于CS1061报错(XX不包含XXX的定义,并且找不到类型为XX的第一个参.....)的一种可能的解决的办法

在我编程中,我遇到了一个这样的报错, ? 可是我引用的product类中又确实定义了这么一个方法, protected void BindPageData(i...

2726
来自专栏跟着阿笨一起玩NET

关于webservice不支持方法重载的解决办法

1021

扫码关注云+社区