/// <summary> /// Given a Match, emits into the StringBuilder the evaluated /// substitution pattern. /// </summary> private void ReplacementImpl(StringBuilder sb, Match match) { for (int i = 0; i < _rules.Count; i++) { int r = _rules[i]; if (r >= 0) // string lookup sb.Append(_strings[r]); else if (r < -Specials) // group lookup sb.Append(match.GroupToStringImpl(-Specials - 1 - r)); else { switch (-Specials - 1 - r) { // special insertion patterns case LeftPortion: sb.Append(match.GetLeftSubstring()); break; case RightPortion: sb.Append(match.GetRightSubstring()); break; case LastGroup: sb.Append(match.LastGroupToStringImpl()); break; case WholeString: sb.Append(match.GetOriginalString()); break; } } } }
/// <summary> /// Returns the replacement result for a single match /// </summary> internal string Replacement(Match match) { var sb = new StringBuilder(); ReplacementImpl(sb, match); return sb.ToString(); }
/// <summary> /// Given a Match, emits into the List{string} the evaluated /// Right-to-Left substitution pattern. /// </summary> private void ReplacementImplRTL(List<string> al, Match match) { for (int i = _rules.Count - 1; i >= 0; i--) { int r = _rules[i]; if (r >= 0) // string lookup al.Add(_strings[r]); else if (r < -Specials) // group lookup al.Add(match.GroupToStringImpl(-Specials - 1 - r)); else { switch (-Specials - 1 - r) { // special insertion patterns case LeftPortion: al.Add(match.GetLeftSubstring()); break; case RightPortion: al.Add(match.GetRightSubstring()); break; case LastGroup: al.Add(match.LastGroupToStringImpl()); break; case WholeString: al.Add(match.GetOriginalString()); break; } } } }
/// <summary> /// Put match in its canonical form before returning it. /// </summary> private Match TidyMatch(bool quick) { if (!quick) { Match match = runmatch; runmatch = null; match.Tidy(runtextpos); return match; } else { // in quick mode, a successful match returns null, and // the allocated match object is left in the cache return null; } }
/// <summary> /// Initializes all the data members that are used by Go() /// </summary> private void InitMatch() { // Use a hashtable'ed Match object if the capture numbers are sparse if (runmatch == null) { if (runregex.caps != null) runmatch = new MatchSparse(runregex, runregex.caps, runregex.capsize, runtext, runtextbeg, runtextend - runtextbeg, runtextstart); else runmatch = new Match(runregex, runregex.capsize, runtext, runtextbeg, runtextend - runtextbeg, runtextstart); } else { runmatch.Reset(runregex, runtext, runtextbeg, runtextend, runtextstart); } // note we test runcrawl, because it is the last one to be allocated // If there is an alloc failure in the middle of the three allocations, // we may still return to reuse this instance, and we want to behave // as if the allocations didn't occur. (we used to test _trackcount != 0) if (runcrawl != null) { runtrackpos = runtrack.Length; runstackpos = runstack.Length; runcrawlpos = runcrawl.Length; return; } InitTrackCount(); int tracksize = runtrackcount * 8; int stacksize = runtrackcount * 8; if (tracksize < 32) tracksize = 32; if (stacksize < 16) stacksize = 16; runtrack = new int[tracksize]; runtrackpos = tracksize; runstack = new int[stacksize]; runstackpos = stacksize; runcrawl = new int[32]; runcrawlpos = 32; }
/* * Convert to a thread-safe object by precomputing cache contents */ /// <summary> /// Returns a Match instance equivalent to the one supplied that is safe to share /// between multiple threads. /// </summary> public static Match Synchronized(Match inner) { if (inner == null) throw new ArgumentNullException(nameof(inner)); int numgroups = inner._matchcount.Length; // Populate all groups by looking at each one for (int i = 0; i < numgroups; i++) { Group group = inner.Groups[i]; // Depends on the fact that Group.Synchronized just // operates on and returns the same instance Group.Synchronized(group); } return inner; }