public void Match(string input, bool matchWholeInput, MatchMode mode, int startOffset, bool ignoreCase, MatchFoundCallback matchFoundCallback, ContinueIterationCallback continueIterationCallback) { if (startOffset < 0) { throw new ArgumentOutOfRangeException("startOffset"); } if (matchFoundCallback == null) { throw new ArgumentNullException("callback"); } int inputLength = String.IsNullOrEmpty(input) ? 0 : input.Length; if (startOffset > inputLength) { return; } int start = _FST.GetStartState(); if (start < 0) { return; } #if DEBUG bool dumpAutomaton = false; if (dumpAutomaton) { _FST.Dump("D:/temp/fst.txt"); } #endif // TODO make sure the FST is not modified during transition // NOTE the match callbacks throw each found match, not just the longest one. The // caller needs to make sure that longer matches are scanned. List <MatchState> states = new List <MatchState>(); bool continueMatchProcess = true; MatchState startState = new MatchState(start); startState.InputPosition = startOffset; states.Add(startState); if (_FST.IsFinal(startState.State)) { if (!matchWholeInput || startState.InputPosition >= inputLength) { continueMatchProcess = matchFoundCallback(startState); } } // remember the number of attempted/tested transitions to send caller a keep-alive signal int ticks = 0; bool logTransitions = false; while (states.Count > 0 && continueMatchProcess) { /* we put the transition target states into a new list so that we don't mess * around with the current one. */ List <MatchState> newStates = new List <MatchState>(); for (int s = states.Count - 1; s >= 0; --s) { MatchState ms = states[s]; State state = _FST.GetState(ms.State); foreach (FSTTransition trans in state.Transitions) { /* * if (state.TransitionsSorted * && !ignoreCase * && (mode == MatchMode.Analyse) * && trans.Input.IsCharLabel * && ms.InputPosition < input.Length * && input[ms.InputPosition] > trans.Input.Symbol) * { * break; * } */ ++ticks; MatchState next; if ((next = ms.Traverse(input, trans, mode, ignoreCase)) != null) { if (logTransitions) { System.Diagnostics.Debug.WriteLine(String.Format("\tTraversing from ({0}, {1}/{2}) to ({3}, {4}/{5}) on {6}", ms.State, ms.InputPosition, ms.ConsumedSymbols, next.State, next.InputPosition, next.ConsumedSymbols, ms.InputPosition < input.Length ? input[ms.InputPosition] : '#')); } newStates.Add(next); if (_FST.IsFinal(next.State)) { if (!matchWholeInput || next.InputPosition >= inputLength) { continueMatchProcess = matchFoundCallback(next); } } } } } states = null; states = newStates; if ((ticks % 1000) == 0 && continueMatchProcess && continueIterationCallback != null) { continueMatchProcess = continueIterationCallback(ticks); } } }
public void Concatenate(FST rhs) { List <int> previouslyFinalStates = GetFinalStates(); if (previouslyFinalStates.Count == 0) { throw new Exception("Automaton does not have any final states"); } if (!StateExists(_StartState)) { throw new Exception("Automaton does not have a start state"); } if (!rhs.StateExists(rhs._StartState)) { throw new Exception("RHS Automaton does not have a start state"); } bool lhsStartWasFinal = IsFinal(_StartState); bool rhsStartWasFinal = rhs.IsFinal(rhs._StartState); // the mapping from the state IDs of the RHS automaton. Key is the // original RHS state ID, Value is the new state ID in the source automaton Dictionary <int, int> stateMapping = new Dictionary <int, int>(); // all previously final states become non-final unless the RHS start state is final if (!rhsStartWasFinal) { foreach (int pf in previouslyFinalStates) { SetFinal(pf, false); } } // copy over the states foreach (KeyValuePair <int, State> rhsState in rhs._States) { int newState = AddState(); stateMapping.Add(rhsState.Value.Id, newState); // final states in the RHS automaton remain final if (rhsState.Value.IsFinal) { SetFinal(newState, true); } } // now that all states exist, copy over the RHS transitions foreach (KeyValuePair <int, State> rhsState in rhs._States) { foreach (FSTTransition t in rhsState.Value.Transitions) { AddTransition(stateMapping[t.Source], stateMapping[t.Target], new Label(t.Input), new Label(t.Output)); } } // next, link the two automatons. // first, each transition which ends in a previously final state is // copied into a transition to the previous start state of RHS int newRhsStart = stateMapping[rhs._StartState]; foreach (KeyValuePair <int, State> lhsState in _States) { State testState = lhsState.Value; List <FSTTransition> transitions = testState.Transitions; // Take care with this iteration as the loop adds to the state's transitions for (int transition = transitions.Count - 1; transition >= 0; --transition) { FSTTransition link = transitions[transition]; if (previouslyFinalStates.Contains(link.Target)) { testState.AddTransition(newRhsStart, new Label(link.Input), new Label(link.Output)); } } } if (lhsStartWasFinal) { // need to introduce an eps transition to the rhs start state AddTransition(_StartState, newRhsStart, new Label(Label.SpecialSymbolEpsilon), new Label(Label.SpecialSymbolEpsilon)); } Clean(); }