protected override bool CompareAndAdvanceImp( string input, int pos, int depth, RunState runState, out int index) { int depthPlusOne = depth + 1; // If the start doesn't match the open then this is not a match if (m_Open.CompareAndAdvance(input, pos, depthPlusOne, runState, out pos)) { // How far down the rabbit hole are we? int nestedDepth = 1; for (; ;) { int currentPos = pos; if (m_Open.CompareAndAdvance(input, currentPos, depthPlusOne, runState, out pos)) { ++nestedDepth; } else if (m_Close.CompareAndAdvance(input, currentPos, depthPlusOne, runState, out pos)) { --nestedDepth; if (nestedDepth == 0) { // Found the end index = pos; return(true); } } else { // Advance by 1 pos = currentPos + 1; } } } index = -1; return(false); }
protected override void PerformImp( string input, int pos, int depth, RunState runState, out int index) { if (!m_Comparison.CompareAndAdvance(input, pos, depth + 1, runState, out index)) { // Reset the position back to the beginning if the comparison is false index = pos; } }
protected override bool CompareAndAdvanceImp( string input, int pos, int depth, RunState runState, out int index) { bool rv = Comparison.CompareAndAdvance(input, pos, depth + 1, runState, out index); if (rv) { // Do the capture Length = index - pos; Captured = input.Substring(pos, Length); BeginPos = pos; EndPos = index; } return(rv); }
protected override bool CompareAndAdvanceImp( string input, int pos, int depth, RunState runState, out int index) { index = -1; // Basically just loop until the comparison returns true bool end = false; int depthPlusOne = depth + 1; for (index = pos; ;) { // Continue?? if (m_ContinueComp != null) { if (!m_ContinueComp.Compare(input, index, depthPlusOne, runState)) { // No. return(false); } } int previousPos = index; end = m_Comparison.CompareAndAdvance(input, index, depthPlusOne, runState, out index); if (end) { return(true); } // If the comparison fails and we are at the end of the string (last char + 1) then cease to continue if (previousPos == input.Length) { return(false); } // Advance by 1 and try again index = previousPos + ((m_Forwards)?1: -1); } }
protected override void PerformImp( string input, int pos, int depth, RunState runState, out int index) { index = -1; // Basically just loop until the comparison returns false bool end = false; int depthPlusOne = depth + 1; for (index = pos; index < input.Length && !end;) { int previousPos = index; end = !m_Comparison.CompareAndAdvance(input, index, depthPlusOne, runState, out index); if (end) { index = previousPos; } } }
//TODO does it make sense to have a list of 0 items? protected override bool CompareAndAdvanceImp( string input, int pos, int depth, RunState runState, out int index) { index = -1; // 'i' keeps track of how many iterations (list items) we've had int i; bool reachedEndOfList = false; int depthPlusOne = depth + 1; for (i = 0;;) { #if DEBUG int dbgPosAtStart = pos; #endif // Skip the line wrap if there is one before the list item m_Options.SkipLineWrap(input, pos, depthPlusOne, runState, out pos); if (pos >= input.Length) { // Reached the end of the input string break; } // Trim left if (ItemTrim != null) { ItemTrim.Perform(input, pos, depthPlusOne, runState, out pos); if (pos >= input.Length) { // Reached the end of the input string break; } } // Do the comparison if (!m_Comparison.CompareAndAdvance(input, pos, depthPlusOne, runState, out pos)) { // This list item does not match so overall it is a fail index = -1; return(false); } // We've had another successful item match ++i; // Skip the line wrap if there is one after the list item m_Options.SkipLineWrap(input, pos, depthPlusOne, runState, out pos); if (pos >= input.Length) { // Reached the end of the input string break; } // Trim right int beforeRightTrim = pos; if (ItemTrim != null) { ItemTrim.Perform(input, pos, depthPlusOne, runState, out pos); if (pos >= input.Length) { // Reached the end of the input string break; } } // Did we reach the seperator/delimiter? int afterSeperator; if (m_Seperator.CompareAndAdvance( input, pos, depthPlusOne, runState, out afterSeperator)) { // Update the index to be after the seperator pos = afterSeperator; // Get another list item } else { // Must have reached the end of the list // Keep the index as the first character of the end - key nuance design decision reachedEndOfList = true; // If we've reached the end of the list, retreat to before the item trim pos = beforeRightTrim; break; } } // Do we have the minimum number of items? bool rv; if (MinAmount.HasValue && i < MinAmount.Value) { rv = false; } // Do we have too many items? else if (MaxAmount.HasValue && i > MaxAmount.Value) { rv = false; } else { rv = reachedEndOfList; } index = pos; return(rv); }
// Returns whether this state is enabled public bool Update( string input, int pos, RunState runState, out int index) { bool orgEnabled = IsEnabled; index = pos; if (IsEnabled) { // Look for the disable state int afterDisable; IsEnabled = !m_Disable.CompareAndAdvance(input, pos, 0, runState, out afterDisable); if (!IsEnabled) { // Skip to after the compare index = afterDisable; } } else { // Look for the enable state int afterEnable; IsEnabled = m_Enable.CompareAndAdvance(input, pos, 0, runState, out afterEnable); if (IsEnabled) { // Skip to after the compare index = afterEnable; } } #if DEBUG // Has become enabled if (!orgEnabled && IsEnabled) { if (pos <= 9279) { //Console.WriteLine(string.Format("enabled: {0}", pos)); } } if (pos == 1374) { Misc.Break(); } #endif #if DEBUG if (Name == @"style=""" || Name == @"table or th") { if (orgEnabled != IsEnabled) { /* * string stringPortion = input.Substring(pos, Math.Min(20, input.Length)); * Console.WriteLine(string.Format("Changed from {0} to {1}. pos: {3} string:\r\n{2}", * orgEnabled, * IsEnabled, * stringPortion, * pos)); */ } } #endif return(IsEnabled); }
protected override bool CompareAndAdvanceImp( string str, int firstIndex, int depth, RunState runState, out int index) { index = -1; // Statement index int stmtIndex; bool failedMatch = false; int pos; int depthPlusOne = depth + 1; for (stmtIndex = 0, pos = firstIndex; !failedMatch && stmtIndex < m_Statements.Count; ++stmtIndex) { // Key nuance design decision. It's OK to perform operations/comparisons even if we have reached the end of // the string. This is necessary for things like setting variables, comparing against the end of the // string e.t.c. No doubt there will be bugs presuming this isn't the case but I've only realised // retrospectively that this is a requirement. IStatement stmt = m_Statements[stmtIndex]; if (stmt is IOperation) { IOperation op = (IOperation)stmt; op.Perform(str, pos, depthPlusOne, runState, out pos); } else { if (stmt is IComparisonWithAdvance) { IComparisonWithAdvance comp = (IComparisonWithAdvance)stmt; int previousPos = pos; if (!comp.CompareAndAdvance(str, pos, depthPlusOne, runState, out pos)) { // This part of the pattern match failed. Start again (using the outer loop/index) but at // the next character failedMatch = true; } } else if (stmt is IComparison) { //sidtodo not sure about this - I'm not sure the design of the statement classes is right IComparison comp = (IComparison)stmt; if (!comp.Compare(str, pos, depthPlusOne, runState)) { failedMatch = true; } } } } // Got this far without a match? if (!failedMatch) { // Did we execute all statements? if (stmtIndex == m_Statements.Count) { // Exclusions? if (Exclusion != null) { string subStr = str.Substring(firstIndex, pos - firstIndex); failedMatch = Exclusion.Compare(subStr, 0, depthPlusOne, runState); } if (!failedMatch) { // Successful match index = pos; } } else { // We did not complete all of the comparisons // Go to the next character // Potentially a speedup here? If we reach the end of the input string but cannot complete all // comparisons then copy the remaining string rather than trying to do any more comparisons? failedMatch = true; } } return(!failedMatch); }
private string Process( string input, string replaceWith, IComparisonWithAdvance mainComparison, Dictionary <string, Capture> capturing, List <State> stateList, bool replace, out int numMatches, Func <RunState, string, int, string> ReplaceFunc = null, Action <RunState> InitRunState = null) { // The replaced string StringBuilder replaced = new StringBuilder(); var runState = new RunState(); if (InitRunState != null) { InitRunState(runState); } numMatches = 0; // Iterate the input string character by character for (int outerIndex = 0; outerIndex < input.Length;) { runState.Clear(); runState.BeginPos = outerIndex; #if DEBUG int dbgInitialOuterIndex = outerIndex; if (dbgInitialOuterIndex == 1374) { Misc.Break(); } string dbgInputPortion = input.Substring(dbgInitialOuterIndex, Math.Min(20, input.Length - dbgInitialOuterIndex)); #endif //// All states enabled? int afterState = outerIndex; bool stateEnabled; if (stateList != null) { for (; ;) { // If the state becomes enabled, check that directly afterwards we don't encounter a close state // Imagine we have a state which opens on '<%' and closes on '%>' and the input string is '<%%> ...' // We enable then instantly disable again. We only stop trying to update the state when updating the // state doesn't advance the position int curIndex = afterState; stateEnabled = UpdateState(stateList, input, afterState, runState, out afterState); if (curIndex == afterState) { // Updating the state did not advance the position - continue with the replace break; } } } else { stateEnabled = true; } // Copy the state string (if any) if (afterState != outerIndex) { string stateString = input.Substring(outerIndex, afterState - outerIndex); replaced.Append(stateString); } // Update the main index outerIndex = afterState; if (outerIndex < input.Length) { bool matched = stateEnabled; if (stateEnabled) { // Run the statements beginning from 'afterState' int innerIndex = outerIndex; int afterMatch; matched = mainComparison.CompareAndAdvance(input, innerIndex, 0, runState, out afterMatch); if (matched) { // The begin of the matching string runState.BeginPos = outerIndex; ++numMatches; // This is a match! :) // Do the replace string iterReplaced = ReplaceMatch(replaceWith, ReplaceFunc, capturing, runState, input, afterMatch); replaced.Append(iterReplaced); LogMatchReplace( input, innerIndex, afterMatch, iterReplaced, capturing); // Update the outer index and continue iterating from there outerIndex = afterMatch; } } if (!matched) { if (replace) { // Match failed: copy this character to the output string and move on to the next one (if this is replace mode) replaced.Append(input[outerIndex]); } ++outerIndex; } } } return(replaced.ToString()); }