- Dependencies:
- <PackageReference Include="System.Memory" Version="4.6.3" />
- <PackageReference Include="System.Collections.Concurrent" Version="4.3.0" />
- (3) Projects:
- DLL Library: <TargetFrameworks>netstandard2.1;net8.0;net481</TargetFrameworks>
- EXE WinForm: .NET Framework 4.8.1
- EXE Console: <TargetFramework>net8.0</TargetFramework>
To use the library it has 1 primary class DiffTool
with 3 static methods with the same return model: ComparisonResults
.
- File Compare, passing file paths into each. This can be Binary or ASCII files. If either are Binary, both will be treated as Binary.
DiffTool.CompareFiles(string sourceFile, string targetFile, double scoreThreshold = 0.30, byte lineLookAhead = 3);
- String Compare, passing old string vs latest string. Threshhold is auto set to 10% to ensure detail for a single line.
DiffTool.CompareString(string srcText, string trgText);
- String Array Compare, also used by File Compare above.
DiffTool.CompareStringArr(string[] linesOld, string[] linesNew, double scoreThreshold = 0.30, byte lineLookAhead = 3);
The library builds a comparison between 2 files, strings, byte, string array, and byte array and returns this Class Model ComparisonResults
. It also allows a threshold and line look ahead option for ASCII files, but ignored for Binary files.
Threshold
- Default and Suggested: 30%-60%. This can be seen in the image above, within the Menu. If the percentage is too low, you might get more detailed, but also can make 2 lines that are nothing alike might show merged, when it's really a deleted line and a new line added in it's place. If the percentage is too high the line might say deleted with a new line instead of a modified line. It really depends on your need.lineLookAhead
- Default and Suggested: 3. Looking to far ahead might mix lines, or make modifications of 1 line look deleted with new lines been added. To low and modifications might not be seen.
public class ComparisonResults
{
/// <summary>
/// Create an empty Model. IsEmpty will be set to True.
/// </summary>
public static ComparisonResults Empty { get; } = new ComparisonResults();
/// <summary>
/// If ComparisonResults wasn't intialized, True will be returned.
/// </summary>
public bool IsEmpty { get; } = false;
/// <summary>
/// If files compared were binary or not.
/// </summary>
public bool IsBinary { get; } = false;
/// <summary>
/// If an Exception occurs when files are to be loaded, this will be set to true.<br/>
/// "Exception" property for this class will be set to exception reason.
/// </summary>
public bool HasException { get { return this.Exception != null; } }
/// <summary>
/// Only used when one of the files is missing when CompareFiles() is called.<br/>
/// <code>
/// if (!sourceFileInfo.Exists)
/// return new ComparisonResults(new ArgumentException($"{nameof(sourceFile)}: '{sourceFile}' is not found and/or accessible."));
/// if (!targetFileInfo.Exists)
/// return new ComparisonResults(new ArgumentException($"{nameof(targetFile)}: '{targetFile}' is not found and/or accessible."));
/// </code>
/// </summary>
public Exception Exception { get; } = null;
/// <summary>
/// Holds each line with each byte showing any differences that may exist.
/// </summary>
public CompareDiff[] LineComparison { get; } = new CompareDiff[0];
/// <summary>
/// Shows how many of each different change types were found.<br/>
/// Add, Modified, Delete, or No Change
/// </summary>
public DiffCounts Diffs { get; } = new DiffCounts(0, 0, 0, 0);
}
public class DiffCounts
{
public int Added { get; } = 0;
public int Deleted { get; } = 0;
public int Modified { get; } = 0;
public int Identical { get; } = 0;
}
public class CompareDiff
{
/// <summary>
/// Create an empty Model. IsEmpty will be set to True.
/// </summary>
public static CompareDiff Empty { get; } = new CompareDiff();
/// <summary>
/// LineBreakDown is used for Modified lines and will be empty for New, Deleted, or unmodified lines.<br/>
/// This is the help translate modified lines in a more structured manner.
/// </summary>
public ByteLevel[] ByteByByteDiff { get { return GetByteLevel(); } }
/// <summary>
/// If CompareDiff wasn't intialized, True will be returned.
/// </summary>
public bool IsEmpty { get { return this.DiffType.Equals(DiffType.None); } }
/// <summary>
/// Type of modification found. Add, Delete, Modified, or None
/// </summary>
public DiffType DiffType { get; } = DiffType.None;
/// <summary>
/// Line number created for UI matching and may not match line numbers in file.
/// </summary>
public int LineNumber { get; } = -1;
/// <summary>
/// Single line in string format.
/// </summary>
public string LineDiffStr { get { return _lineDiffStr; } }
/// <summary>
/// Encoding used for string to byte[] and back to string conversion.<br/>
/// Default: UTF8
/// </summary>
public Encoding EncodeType { get; } = _defaultEncoding;
}
public class ByteLevel
{
/// <summary>
/// Byte state: None, Added, Modified, Deleted
/// </summary>
public DiffType DiffType { get; } = DiffType.None;
/// <summary>
/// Char representation of the byte.
/// </summary>
public char Char { get; } = '\0';
/// <summary>
/// Single character string representation of the byte.
/// </summary>
public string Str { get; } = string.Empty;
/// <summary>
/// Byte found in file.
/// </summary>
public byte Byte { get; } = 0;
/// <summary>
/// Hex version of the Byte
/// </summary>
public string Hex { get; } = string.Empty;
}
The property LineComparison
returns a line by line array for side by side look for users that want to build their own UI.
Model CompareDiff
has ByteByByteDiff
, that breaks down a line by character when modified, as seen on Line 8 of the above image.
Example: this is a test
<--> that was a test
- CompareDiff.LineDiffStr:
th[-i][+a][-s][+t] [-i][+w][+a]s a test
- CompareDiff.ByteByByteDiff: (Will look cleaner)
t
- CharDiff.DiffType.Modifiedh
- CharDiff.DiffType.Modifiedi
- CharDiff.DiffType.Deleteda
- CharDiff.DiffType.Addeds
- CharDiff.DiffType.Deletedt
- CharDiff.DiffType.Addedi
- CharDiff.DiffType.Deletedw
- CharDiff.DiffType.Addeda
- CharDiff.DiffType.Addeds
- CharDiff.DiffType.Modifieda
- CharDiff.DiffType.Modifiedt
- CharDiff.DiffType.Modifiede
- CharDiff.DiffType.Modifieds
- CharDiff.DiffType.Modifiedt
- CharDiff.DiffType.Modified