/// <summary> /// Finds all the common elements in all the loaded collections and returns a list. Might want to override if the /// diff produces diff elements of a different type /// </summary> /// <returns>The collection of common elements</returns> public virtual IDiffObjectsCollection FindCommonElements() { int n = _collections.Count; IDiffObjectsCollection commonElements = _collections[0]; for (int i = 1; i < n; i++) { //disable merges for this diff bool allowMerges = _properties.AllowMerges; _properties.AllowMerges = false; DoDiff(commonElements, _collections[i]); _properties.AllowMerges = allowMerges; //replace the current collection with the common elements collection //at the next iteration the next element in the collection will be compared against the common elements commonElements = _collections[i].CommonElements; if (commonElements.Count == 0) { return(commonElements); //return an empty collection, there are no common elements } //sort the elements by position commonElements.SortByPosition(); } return(commonElements); //the last element will hold all the common elements }
public void PushRange(IDiffObjectsCollection collection) { if (collection != null) { Items.InsertRange(0, collection.Items); } }
/// <summary> /// Executes the diff operation between the specified indexes of the collections list /// </summary> /// <param name="indexOfFirst">The index of the first element to diff</param> /// <param name="indexOfSecond">The index of the second element to diff</param> public double DoDiff(int indexOfFirst, int indexOfSecond) { IDiffObjectsCollection first = _collections[indexOfFirst]; IDiffObjectsCollection second = _collections[indexOfSecond]; return(DoDiff(first, second)); }
/// <summary> /// Check if the values match and outputs a set of granular differences /// </summary> /// <param name="diffObject"></param> /// <param name="diffsForSelf"></param> /// <param name="diffsForArgument"></param> /// <returns></returns> public bool ValueMatches(IDiffObject diffObject, out IDiffObjectsCollection diffsForSelf, out IDiffObjectsCollection diffsForArgument, out IDiffObjectsCollection commonElements) { HeaderDiffObject otherObject = diffObject as HeaderDiffObject; diffsForSelf = null; diffsForArgument = null; commonElements = null; bool matches = false; if (otherObject != null) { matches = _headerLineHash == otherObject.HeaderLineHash; //if the values are different but the headers are the same if (!matches && String.Compare(_name, otherObject.Name, true) == 0) { WordsDiffer valuesDiffer = new WordsDiffer(); valuesDiffer.AddTask(_values); valuesDiffer.AddTask(otherObject.Values); valuesDiffer.Properties.Sorted = true; valuesDiffer.Properties.CaseInSensitiveSort = true; double diffRatio = valuesDiffer.DoDiff(0, 1); diffsForSelf = valuesDiffer.GetResultingDifferences(0); diffsForArgument = valuesDiffer.GetResultingDifferences(1); commonElements = valuesDiffer.GetResultingCommonElements(0); matches = diffRatio >= _valuesMinSimilarity; } } return(matches); }
public void WordsDiff() { string text1 = "first second;third1"; string text2 = "second;first fourth-third"; WordsDiffer differ = new WordsDiffer(); DiffResult result = differ.DoDiff(text1, text2); IDiffObjectsCollection firstDiffs = result.DifferencesForFirst; IDiffObjectsCollection secondDiffs = result.DifferencesForSecond; Assert.IsTrue(firstDiffs[0].ValueEquals(new WordDiffObject(0, 0, "first "))); Assert.IsTrue(firstDiffs[1].ValueEquals(new LetterDiffObject(0, 0, "1"))); Assert.IsTrue(secondDiffs[0].ValueEquals(new WordDiffObject(0, 0, "first "))); Assert.IsTrue(secondDiffs[1].ValueEquals(new WordDiffObject(0, 0, "fourth-"))); //test a sorted diff differ.Properties.Sorted = true; result = differ.DoDiff(text1, text2); firstDiffs = result.DifferencesForFirst; secondDiffs = result.DifferencesForSecond; Assert.IsTrue(firstDiffs[0].ValueEquals(new LetterDiffObject(0, 0, "1"))); Assert.IsTrue(secondDiffs[0].ValueEquals(new WordDiffObject(0, 0, "fourth-"))); }
public void LinesDiff() { string text1 = "LineLine1.1\r\n" + "eniLLine1.3\r\n" + "ABC1.4"; string text2 = "LineLine2.1\r\n" + "XYZ2.4\r\n" + "eniLLine2.3"; LinesDiffer differ = new LinesDiffer(); DiffResult result = differ.DoDiff(text1, text2); IDiffObjectsCollection firstDiffs = result.DifferencesForFirst; IDiffObjectsCollection secondDiffs = result.DifferencesForSecond; firstDiffs.SortByPosition(); secondDiffs.SortByPosition(); Assert.IsTrue(firstDiffs[0].ValueEquals(new LetterDiffObject(0, 0, "1"))); Assert.IsTrue(secondDiffs[0].ValueEquals(new LetterDiffObject(0, 0, "2"))); Assert.IsTrue(firstDiffs[1].ValueEquals(new LetterDiffObject(0, 0, "1"))); Assert.IsTrue(secondDiffs[1].ValueEquals(new LineDiffObject(0, 0, "XYZ2.4"))); Assert.IsTrue(firstDiffs[2].ValueEquals(new LineDiffObject(0, 0, "ABC1.4"))); Assert.IsTrue(secondDiffs[2].ValueEquals(new LetterDiffObject(0, 0, "2"))); }
public void AddRange(IDiffObjectsCollection collection) { if (collection != null) { Items.AddRange(collection.Items); } }
private string PrintTextDifferences(IDiffObjectsCollection diff) { StringBuilder result = new StringBuilder(); for (int i = 0; i < diff.Count; i++) { result.Append((diff[i] as BaseTextDiffObject).Value); result.Append(" "); } return(result.ToString()); }
private string GetRtf(string text, IDiffObjectsCollection differences) { int i, n = differences.Count; RtfHighlight[] diffHighlights = new RtfHighlight[n]; for (i = 0; i < n; i++) { diffHighlights[i] = new RtfHighlight(differences[i]); diffHighlights[i].Color = TVColorConverter.GetColorFromString(TrafficViewerOptions.Instance.ColorDiffText); } return(_builder.Convert(text, diffHighlights)); }
public void LettersDiff() { string text1 = "abcdefg;1"; string text2 = "xabcdfg1!"; LettersDiffer differ = new LettersDiffer(); DiffResult result = differ.DoDiff(text1, text2); IDiffObjectsCollection firstDiffs = result.DifferencesForFirst; IDiffObjectsCollection secondDiffs = result.DifferencesForSecond; Assert.IsTrue(firstDiffs[0].ValueEquals(new LetterDiffObject(0, 0, "e"))); Assert.IsTrue(firstDiffs[1].ValueEquals(new LetterDiffObject(0, 0, ";"))); Assert.IsTrue(secondDiffs[0].ValueEquals(new LetterDiffObject(0, 0, "x"))); Assert.IsTrue(secondDiffs[1].ValueEquals(new LetterDiffObject(0, 0, "!"))); }
/// <summary> /// Diffs the two collections using the ValueEquals function of their elements and stores differences in the /// arguments collection /// </summary> /// <param name="first"></param> /// <param name="second"></param> public double Diff(ref IDiffObjectsCollection first, ref IDiffObjectsCollection second) { double similarity = 0.0; if ((first == null || first.Count == 0) && second != null) { second.Differences = second; } else if ((second == null || second.Count == 0) && first != null) { first.Differences = first; } else { //use the LCS algorith to compute the longest common subsequence and populate the Differences in first and second similarity = LCS(ref first, ref second); } return(similarity); }
protected double DoDiff(IDiffObjectsCollection first, IDiffObjectsCollection second) { first.InitDiffs(); second.InitDiffs(); first.InitCommonElements(); second.InitCommonElements(); if (_properties.Sorted) { first.SortByValues(_properties.CaseInSensitiveSort); second.SortByValues(_properties.CaseInSensitiveSort); //replace the default LCS algorithm with a simple algorithm for sorted collections _algorithm = new SortedCollectionsDiffAlgorithm(); } first.AllowMerges = _properties.AllowMerges; second.AllowMerges = _properties.AllowMerges; return(_algorithm.Diff(ref first, ref second)); }
/// <summary> /// Checks is the value is equal. If not where applicable a collection of granular differences is outputed /// </summary> /// <param name="diffObject"></param> /// <param name="diffsForSelf"></param> /// <param name="diffsForArgument"></param> /// <param name="commonElements"></param> /// <returns></returns> public bool ValueMatches(IDiffObject diffObject, out IDiffObjectsCollection diffsForSelf, out IDiffObjectsCollection diffsForArgument, out IDiffObjectsCollection commonElements) { BaseTextDiffObject otherObject = diffObject as BaseTextDiffObject; diffsForSelf = null; diffsForArgument = null; commonElements = null; bool matches = false; if (otherObject != null) { matches = this.ValueHash == otherObject.ValueHash; if (!matches) { double simFactor = ASESimilarityAlgorithm.CalculateSimilarity(this.Value, otherObject.Value); LettersDiffer granularDiffer = InitGranularDiffer(); if (simFactor > 0 && granularDiffer != null) { //calculate granular differences granularDiffer.AddTask(Value, Position); //imports the current word into a letters collection starting from the position of the current element granularDiffer.AddTask(otherObject.Value, otherObject.Position); double diffRatio = granularDiffer.DoDiff(0, 1); diffsForSelf = granularDiffer.GetResultingDifferences(0); diffsForArgument = granularDiffer.GetResultingDifferences(1); commonElements = granularDiffer.GetResultingCommonElements(0); matches = diffRatio >= this.SimilarityFactor; } } } return(matches); }
private void DiffWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { _progress.Visible = false; _timer.Stop(); RequestsDifferResult result = e.Result as RequestsDifferResult; if (result != null) { _labelSimilarity.Text = String.Format(Properties.Resources.SimilarityText, result.BodyAproximateSimilarity * 100); _firstDiffs = result.DiffsForFirst; _secondDiffs = result.DiffsForSecond; _boxFirst.Rtf = GetRtf(result.FirstText, result.DiffsForFirst); _boxSecond.Rtf = GetRtf(result.SecondText, result.DiffsForSecond); } //re-enable the diff buttons DiffButtonsSwitch(true); _diffInProgress = false; }
/// <summary> /// Computes the longest common subsequence matrix between the two collections /// </summary> /// <param name="first"></param> /// <param name="second"></param> private double LCS(ref IDiffObjectsCollection first, ref IDiffObjectsCollection second) { int start = 0; int firstEnd = first.Count; int secondEnd = second.Count; int i, j, n, m; IDiffObjectsCollection granularDiffsForFirst = null; IDiffObjectsCollection granularDiffsForSecond = null; IDiffObjectsCollection granularCommonElements = null; IDiffObjectsCollection currCommonElements = first.CommonElements; second.CommonElements = currCommonElements; //trim the matching items at the beggining while (start < firstEnd && start < secondEnd && first[start].ValueMatches(second[start], out granularDiffsForFirst, out granularDiffsForSecond, out granularCommonElements)) { //if the collections were slightly different add the small differences first.Differences.AddRange(granularDiffsForFirst); second.Differences.AddRange(granularDiffsForSecond); if (granularDiffsForFirst == null && granularDiffsForSecond == null) { currCommonElements.Add(first[start]); } else { currCommonElements.AddRange(granularCommonElements); } start++; } //trim the matching items at the end while (firstEnd > start && secondEnd > start && first[firstEnd - 1].ValueMatches(second[secondEnd - 1], out granularDiffsForFirst, out granularDiffsForSecond, out granularCommonElements)) { firstEnd--; secondEnd--; if (granularDiffsForFirst == null && granularDiffsForSecond == null) { currCommonElements.Add(first[firstEnd]); } else { currCommonElements.AddRange(granularCommonElements); } //if the collections were slightly different insert the small differences first.Differences.PushRange(granularDiffsForFirst); second.Differences.PushRange(granularDiffsForSecond); } m = firstEnd - start + 1; n = secondEnd - start + 1; //truncate the matrix to prevent OOM m = Math.Min(m, MAX_MATRIX_LENGTH); n = Math.Min(n, MAX_MATRIX_LENGTH); //create the matrix for LCS ushort[,] C = new ushort[m, n]; for (i = 1; i < m; i++) { for (j = 1; j < n; j++) { if (first[start + i - 1].ValueMatches(second[start + j - 1])) { C[i, j] = (ushort)(C[i - 1, j - 1] + 1); } else { C[i, j] = Math.Max(C[i, j - 1], C[i - 1, j]); } } } //populate the differences return(ExtractDiffs(C, first, second, start, m, n)); }
/// <summary> /// Adds a task to be compared /// </summary> /// <param name="task"></param> /// <returns>Index of the added task</returns> public int AddTask(IDiffObjectsCollection task) { _collections.Add(task); return(_collections.Count - 1); }
private double ExtractDiffs( ushort[, ] C, IDiffObjectsCollection first, IDiffObjectsCollection second, int start, int m, int n) { int i = m - 1, j = n - 1; double diffCount1 = 0; double diffCount2 = 0; IDiffObjectsCollection currFirstDiffs = first.Differences; IDiffObjectsCollection currSecondDiffs = second.Differences; IDiffObjectsCollection currCommonElements = first.CommonElements; second.CommonElements = currCommonElements; do { int iIndex = start + i - 1; int jIndex = start + j - 1; IDiffObject currFirst = null; IDiffObject currSecond = null; IDiffObjectsCollection granularDiffsForFirst = null; IDiffObjectsCollection granularDiffsForSecond = null; IDiffObjectsCollection granularCommonElements = null; if (iIndex >= 0 && iIndex < first.Count) { currFirst = first[iIndex]; } if (jIndex >= 0 && jIndex < second.Count) { currSecond = second[jIndex]; } if (currFirst != null && currFirst.ValueMatches(currSecond, out granularDiffsForFirst, out granularDiffsForSecond, out granularCommonElements)) { //ValuesMatch can return true if the objects are very similar //In that case we need to capture granular differences currFirstDiffs.PushRange(granularDiffsForFirst); currSecondDiffs.PushRange(granularDiffsForSecond); if (granularDiffsForFirst == null && granularDiffsForSecond == null) { currCommonElements.Add(currFirst); } else { currCommonElements.AddRange(granularCommonElements); } i--; j--; } else if (j > 0 && (i <= 0 || C[i, j - 1] >= C[i - 1, j])) { currSecondDiffs.Push(currSecond); diffCount2++; j--; } else if (i > 0 && (j <= 0 || C[i, j - 1] < C[i - 1, j])) { currFirstDiffs.Push(currFirst); diffCount1++; i--; } }while (i > 0 || j > 0); //calculate diff ratio, or similarity factor double ratio1 = 0; if (first.Count > 0) { ratio1 = 1 - diffCount1 / first.Count; } double ratio2 = 0; if (second.Count > 0) { ratio2 = 1 - diffCount2 / second.Count; } return(Math.Min(ratio1, ratio2)); }
public double Diff(ref IDiffObjectsCollection first, ref IDiffObjectsCollection second) { int i = 0, j = 0, m = first.Count, n = second.Count; double diffCount1 = 0; double diffCount2 = 0; IDiffObjectsCollection granularDiffs1 = null; IDiffObjectsCollection granularDiffs2 = null; IDiffObjectsCollection granularCommon = null; IDiffObjectsCollection currCommonElements = first.CommonElements; second.CommonElements = currCommonElements; while (i < m || j < n) { if (j < n && i < m && first[i].ValueMatches(second[j], out granularDiffs1, out granularDiffs2, out granularCommon)) { first.Differences.AddRange(granularDiffs1); second.Differences.AddRange(granularDiffs2); if (granularDiffs1 == null && granularDiffs2 == null) { currCommonElements.Add(first[i]); } else { currCommonElements.AddRange(granularCommon); } i++; j++; } else if (i < m && (j >= n || first[i].CompareValues(second[j], _ignoreCase) == CompareResult.Lower)) { first.Differences.Add(first[i]); diffCount1++; i++; } else if (j < n && (i >= m || first[i].CompareValues(second[j], _ignoreCase) == CompareResult.Greater)) { second.Differences.Add(second[j]); diffCount2++; j++; } } //calculate diff ratio, or similarity factor double ratio1 = 0; if (first.Count > 0) { ratio1 = 1 - diffCount1 / first.Count; } double ratio2 = 0; if (second.Count > 0) { ratio2 = 1 - diffCount2 / second.Count; } return(Math.Min(ratio1, ratio2)); }