protected static void BuildModificationData(ModificationData A, ModificationData B) { int N = A.HashedPieces.Length; int M = B.HashedPieces.Length; int MAX = M + N + 1; var forwardDiagonal = new int[MAX + 1]; var reverseDiagonal = new int[MAX + 1]; BuildModificationData(A, 0, N, B, 0, M, forwardDiagonal, reverseDiagonal); }
private static void CreatePieceHashes(IDictionary <string, int> pieceHash, ModificationData data, bool ignoreWhitespace, bool ignoreCase, Func <string, string[]> chunker) { string[] pieces; if (string.IsNullOrEmpty(data.RawData)) { pieces = new string[0]; } else { pieces = chunker(data.RawData); } data.Pieces = pieces; data.HashedPieces = new int[pieces.Length]; data.Modifications = new bool[pieces.Length]; for (int i = 0; i < pieces.Length; i++) { string piece = pieces[i]; if (ignoreWhitespace) { piece = piece.Trim(); } if (ignoreCase) { piece = piece.ToUpperInvariant(); } if (pieceHash.ContainsKey(piece)) { data.HashedPieces[i] = pieceHash[piece]; } else { data.HashedPieces[i] = pieceHash.Count; pieceHash[piece] = pieceHash.Count; } } }
private static void BuildModificationData(ModificationData A, int startA, int endA, ModificationData B, int startB, int endB, int[] forwardDiagonal, int[] reverseDiagonal) { while (startA < endA && startB < endB && A.HashedPieces[startA].Equals(B.HashedPieces[startB])) { startA++; startB++; } while (startA < endA && startB < endB && A.HashedPieces[endA - 1].Equals(B.HashedPieces[endB - 1])) { endA--; endB--; } int aLength = endA - startA; int bLength = endB - startB; if (aLength > 0 && bLength > 0) { EditLengthResult res = CalculateEditLength(A.HashedPieces, startA, endA, B.HashedPieces, startB, endB, forwardDiagonal, reverseDiagonal); if (res.EditLength <= 0) { return; } if (res.LastEdit == Edit.DeleteRight && res.StartX - 1 > startA) { A.Modifications[--res.StartX] = true; } else if (res.LastEdit == Edit.InsertDown && res.StartY - 1 > startB) { B.Modifications[--res.StartY] = true; } else if (res.LastEdit == Edit.DeleteLeft && res.EndX < endA) { A.Modifications[res.EndX++] = true; } else if (res.LastEdit == Edit.InsertUp && res.EndY < endB) { B.Modifications[res.EndY++] = true; } BuildModificationData(A, startA, res.StartX, B, startB, res.StartY, forwardDiagonal, reverseDiagonal); BuildModificationData(A, res.EndX, endA, B, res.EndY, endB, forwardDiagonal, reverseDiagonal); } else if (aLength > 0) { for (int i = startA; i < endA; i++) { A.Modifications[i] = true; } } else if (bLength > 0) { for (int i = startB; i < endB; i++) { B.Modifications[i] = true; } } }
/// <summary> /// Creates a result containing the differences between the two given strings, using a given predicate to split the strings. /// </summary> /// <returns>A model holding all the differences.</returns> /// <param name="firstText">First text.</param> /// <param name="secondText">Second text.</param> /// <param name="ignoreWhiteSpace">If set to <c>true</c> ignore white space.</param> /// <param name="ignoreCase">If set to <c>true</c> ignore case.</param> /// <param name="stringSplitter">Predicate used to split the strings in pieces for comparison.</param> public Result CreateCustomDifferences(string firstText, string secondText, bool ignoreWhiteSpace, bool ignoreCase, Func <string, string[]> stringSplitter) { if (firstText == null) { throw new ArgumentNullException("Given first text is null"); } if (secondText == null) { throw new ArgumentNullException("Given second text is null"); } if (stringSplitter == null) { throw new ArgumentNullException("The provided splitter predicate is null"); } var pieceHash = new Dictionary <string, int>(); var lineDifferences = new List <Block>(); var modificationFirst = new ModificationData(firstText); var modificationSecond = new ModificationData(secondText); CreatePieceHashes(pieceHash, modificationFirst, ignoreWhiteSpace, ignoreCase, stringSplitter); CreatePieceHashes(pieceHash, modificationSecond, ignoreWhiteSpace, ignoreCase, stringSplitter); BuildModificationData(modificationFirst, modificationSecond); int lengthFirstPieces = modificationFirst.HashedPieces.Length; int lengthSecondPieces = modificationSecond.HashedPieces.Length; int positionFirst = 0, positionSecond = 0; do { while (positionFirst < lengthFirstPieces && positionSecond < lengthSecondPieces && !modificationFirst.Modifications[positionFirst] && !modificationSecond.Modifications[positionSecond]) { positionFirst++; positionSecond++; } int startOfFirst = positionFirst; int startOfSecond = positionSecond; for (; positionFirst < lengthFirstPieces && modificationFirst.Modifications[positionFirst]; positionFirst++) { ; } for (; positionSecond < lengthSecondPieces && modificationSecond.Modifications[positionSecond]; positionSecond++) { ; } int numberRemoved = positionFirst - startOfFirst; int numberInsertd = positionSecond - startOfSecond; if (numberRemoved > 0 || numberInsertd > 0) { lineDifferences.Add(new Block(startOfFirst, numberRemoved, startOfSecond, numberInsertd)); } } while (positionFirst < lengthFirstPieces && positionSecond < lengthSecondPieces); return(new Result(modificationFirst.Pieces, modificationSecond.Pieces, lineDifferences)); }