Question: xz[[cenvENVzxcENV] [fffff] dsbgENV[fecccccc]nqe W3]NBENV[]ZXC
There are three variable areas in this string, which need to be decomposed by the state machine to find variables.
In order to use state machine, it is necessary to define the number of states of the system and the transition process and conditions between states.
In this case, a total of six states are defined
common char: common string
env: Variable content
over: state machine termination (string length)
maybe: may belong to a variable
Maybe Over: Possibly variables follow.
envOver: Variable termination.
The direct transition relationship between States is shown in Figure 1.
Code:
State Machine Definition:
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; } //The latter state u IList<IState<T>> Nexts { get; set; } //Judging how states migrate Func<IState<T>, T, int, IState<T>> Selector { get; set; } } public interface IContext<T> : IEnumerator<T>, IEnumerable<T> { /// <summary> /// Initial value /// </summary> T OriginData { get; set; } /// <summary> /// Used to customize write processing during state machine changes /// </summary> IDictionary<Tuple<IState<T>, IState<T>>, HandleType<T>> Handles { get; set; } /// <summary> /// Current status /// </summary> IState<T> CurrentState { get; set; } /// <summary> /// Preceding Processing /// </summary> /// <param name="next"></param> /// <returns></returns> bool transition(IState<T> next); } public class State : IState<string> { /// <summary> /// State type /// </summary> public string Name { get; set; } /// <summary> /// Values used to save this state process /// </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; } } 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("Initial state must be set"); 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; // To detect redundant calls protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { // TODO: Release the managed state (managed object). } // TODO: Release unmanaged resources (unmanaged objects) and replace finalizers in the following. // TODO: Set the large field to null. disposedValue = true; } } void IDisposable.Dispose() { // Do not change this code. Put the cleanup code into the above Dispose(bool disposing). Dispose(true); // TODO: If you replace the finalizer in the above content, uncomment the following line. // GC.SuppressFinalize(this); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return this; } IEnumerator IEnumerable.GetEnumerator() { return this; } #endregion }
State Machine State Definition Machine Transition Relation
//Save the value and corresponding state when the state changes var dic = new List<Tuple<string, string>>(); //Define six state instances 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" }; //Initialization state machine IContext<string> stringState = new Context<string> { CurrentState = common }; stringState.OriginData = ""; //Additional processing 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); }; //Coverage processing 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 takes the value of the previous state 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 State Transition and Processing Method under Different Transition Conditions 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 state transition and processing methods under different transition conditions 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 state transition and processing methods under different transition conditions 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); // Maybe Over State Transition and Processing Method under Different Transition Conditions 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 State Transition and Processing Method under Different Transition Conditions 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 State Transition and Processing Method under Different Transition Conditions 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);
Test:
Console.WriteLine("Test string"); 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("current state{0}---Current value{1}", stringState.CurrentState.Name, item); } Console.WriteLine(""); Console.WriteLine(""); Console.WriteLine("Extracted Symbol"); dic.ForEach(a => { Console.WriteLine("String type:" + a.Item1 + "-------------Decomposition value:" + a.Item2); }); }
Test results:
Test string XZ [[cenvENVzxcENV [fffff] dsbgENV [fecccccc] nqe W3] NBENV [] ZXC Current status common char -- current value x Current status common char -- current value xz Current status common char -- current value xz[ Current status common char -- current value xz[[ Current status common char -- current value xz[[c] Current status common char -- current value xz[[ce] Current status common char -- current value xz[[cen] Current status common char -- current value xz[[cenv] Current state maybe -- current value E Current state maybe -- current value EN Current state maybe -- current value ENV Current status common char -- current value z Current status common char -- current value zx Current status common char -- current value zxc Current state maybe -- current value E Current state maybe -- current value EN Current state maybe -- current value ENV Current status maybe Over -- current value[ Current state env -- current value Current state env -- current value Current state env -- current value Current state env -- current value Current state env -- current value Current state env -- current value Current state env -- current value f Current state env -- current value ff Current state env -- current value fff Current state env -- current value ffff Current state env -- current value fffff Current state env -- current value fffff Current state env -- current value fffff Current state envOver -- current value] Current status common char -- current value d Current status common char -- current value ds Current status common char -- current value dsb Current status common char -- current value dsbg Current state maybe -- current value E Current state maybe -- current value EN Current state maybe -- current value ENV Current status maybe Over -- current value[ Current state env -- current value f Current state env -- current value fe Current state env -- current value fec Current state env -- current value fecc Current state env -- current value feccc Current state env -- current value fecccc Current state env -- current value feccccc Current state env -- current value fecccccc Current state envOver -- current value] Current status common char -- current value n Current status common char -- current value nq Current status common char -- current value nqe Current status common char -- current value nqe Current status common char -- current value nqe Current status common char -- current value nqe W Current status common char -- current value nqe W3 Current status common char -- current value nqe W3] Current status common char -- current value nqe W3]N Current status common char -- current value nqe W3]NB Current state maybe -- current value E Current state maybe -- current value EN Current state maybe -- current value ENV Current status maybe Over -- current value[ Current state envOver -- current value[ Current status common char -- current value Z Current status common char -- current value ZX Current status common char -- current value ZXC Current status over -- current value ZXC Extracted Symbol String type: common char----------------------------- decomposition value: xz[[cenv] String type: maybe--------------------------- decomposition value: ENV String type: common char--------------------------- decomposition value: zxc String type: maybe--------------------------- decomposition value: ENV String type: maybeOver--------------------------------- decomposition value:[ String type: env----------------------- decomposition value: fffff String type: envOver------------------------- decomposition value:] String type: common char--------------------------- decomposition value: dsbg String type: maybe--------------------------- decomposition value: ENV String type: maybeOver--------------------------------- decomposition value:[ String type: env--------------------------- decomposition value: fecccccc String type: envOver------------------------- decomposition value:] String type: common char--------------------------- decomposition value: nqe W3] NB String type: maybe--------------------------- decomposition value: ENV String type: envOver------------------------- decomposition value:] String type: common char--------------------------- decomposition value: ZXC