public static (int[] match, float score) FuzzyMatch(IReadOnlyList <string> wmPattern, IReadOnlyList <string> wmText, int loc, FuzzyMatchOptions options = default, LineRange[] ranges = default) { if (ranges == null) { ranges = new LineRange[] { new LineRange { length = wmText.Count } } } ; options ??= new(); // we're creating twice as many MatchMatrix objects as we need, incurring some wasted allocation and setup time, but it reads easier than trying to precompute all the edge cases var fwdMatchers = ranges.Select(r => new MatchMatrix(wmPattern, wmText, options.MaxMatchOffset, r)).SkipWhile(m => loc > m.WorkingRange.last).ToArray(); var revMatchers = ranges.Reverse().Select(r => new MatchMatrix(wmPattern, wmText, options.MaxMatchOffset, r)).SkipWhile(m => loc < m.WorkingRange.first).ToArray(); int warnDist = OffsetWarnDistance(wmPattern.Count, wmText.Count); float penaltyPerLine = options.EnableDistancePenalty ? 1f / (10 * warnDist) : 0; var fwd = new MatchRunner(loc, 1, fwdMatchers, penaltyPerLine); var rev = new MatchRunner(loc, -1, revMatchers, penaltyPerLine); float bestScore = options.MinMatchScore; int[] bestMatch = null; while (fwd.Step(ref bestScore, ref bestMatch) | rev.Step(ref bestScore, ref bestMatch)) { ; } return(bestMatch, bestScore); }
private LineRange TrimRange(LineRange range) { int start = 0; while (start < diffs.Count && diffs[start].op == Operation.EQUAL) { start++; } if (start == diffs.Count) { return new LineRange { start = range.start, length = 0 } } ; int end = diffs.Count; while (end > start && diffs[end - 1].op == Operation.EQUAL) { end--; } return(new LineRange { start = range.start + start, end = range.end - (diffs.Count - end) }); }
public MatchRunner(int loc, int dir, MatchMatrix[] mms, float penaltyPerLine) { this.loc = loc; this.dir = dir; this.mms = mms; this.penaltyPerLine = penaltyPerLine; active = new LineRange(); penalty = -0.1f; // start penalty at -10%, to give some room for finding the best match if it's not "too far" }
private (int[] match, float score) FindMatch(int loc, IReadOnlyList <string> wmContext) { // fuzzy matching is more complex because we need to split up the patched file to only search _between_ previously applied patches var keepoutRanges = patches.Select(p => p.KeepoutRange2).Where(r => r != null).Select(r => r.Value); // parts of file to search in var ranges = new LineRange { length = wmLines.Count }.Except(keepoutRanges).ToArray(); return(FuzzyMatch(wmContext, wmLines, loc, FuzzyOptions, ranges)); }
public StraightMatch(IReadOnlyList <string> pattern, IReadOnlyList <string> search, LineRange range) { patternLength = pattern.Count; this.pattern = pattern; this.search = search; this.range = range; nodes = new MatchNodes[patternLength]; for (int i = 0; i < patternLength; i++) { nodes[i] = new MatchNodes(); } }
private bool CanApplySafelyAt(int loc, Patch patch) { if (loc >= ModifiedRange.end) { return(true); } var range = new LineRange { start = loc, length = patch.length1 }; return(patches.All(p => !p.KeepoutRange2?.Contains(range) ?? true)); }
public MatchMatrix(IReadOnlyList <string> pattern, IReadOnlyList <string> search, int maxOffset = DefaultMaxOffset, LineRange range = default) { if (range == default) { range = new LineRange { length = search.Count } } ; patternLength = pattern.Count; this.range = range; this.maxOffset = maxOffset; WorkingRange = new LineRange { first = range.start - maxOffset, last = range.end - patternLength }; matches = new StraightMatch[maxOffset + 1]; for (int i = 0; i <= maxOffset; i++) { matches[i] = new StraightMatch(pattern, search, range); } }
public static IReadOnlyList <T> Slice <T>(this IReadOnlyList <T> list, LineRange range) => range.start == 0 && range.length == list.Count ? list : new ReadOnlyListSlice <T>(list, range);
public ReadOnlyListSlice(IReadOnlyList <T> wrapped, LineRange range) { this.wrapped = wrapped; this.range = range; }