Text Diff Tool

Compare two texts side by side with highlighted additions, deletions, and unchanged content.

Original
New

Text diff is not "spot the difference" - it turns change size into a measurable metric

Text diff is often treated as a naked-eye game of "where do these two versions differ", but from an engineering and information-retrieval view it really answers three measurable questions: how big is the change, where is it distributed, and how similar are the two versions. This tool runs a line-by-line LCS (Longest Common Subsequence) pass, anchors on identical lines, and flags lines present in only one side as added or deleted. It outputs four counts (unchanged, added, deleted, total changed) and a similarity view - not a vague "they are different". Once you internalize that, you can use the result as a review checklist, a merge basis, or a quality gate instead of a highlight effect.

Algorithm family: four mainstream diff algorithms, each with a strength

Every diff tool is a different solution to the same problem - how to efficiently find "what changed and what stayed" between two sequences. The table below puts four common algorithms side by side. The point is not to memorize complexities but to understand why one tool is fast for a one-line edit while another handles heavily reshuffled code better.

AlgorithmCore ideaBest forBest caseWorst case
LCS (Longest Common Subsequence)Dynamic programming for the longest common subsequence as anchorShort text, teaching demos, side-by-sideO(m+n)O(m×n)
Myers O(ND)Shortest edit path on the edit graphCode version diff, Git's engineO(N)O((N+D)×D)
Patience DiffPatient matching on unique, increasing anchor linesCode moved or reordered a lot~O(n log n)~O(n log n)
Histogram DiffWeights lines by frequency, then picks anchorsLarge files, log/data with repeats~O(n log n)~O(n log n)

Note: m and n are the line counts of each side; N is the total size of both versions and D is the actual difference. This tool uses LCS because it is intuitive and produces "keep the common, show the rare" output that matches human intuition for whole-text, config, and document comparison. When you deal with code that has been heavily moved or reordered, Myers / Patience / Histogram (the strategies behind GNU diffutils and Git) are usually a better fit.

Granularity: line / word / character / glyph

A diff's "granularity" decides what counts as one indivisible comparison unit. Coarser granularity (by line) gives cleaner output and better performance but hides intra-line edits; finer granularity (by character, by glyph) locates exactly which character changed but adds noise. The table below weighs the four options.

GranularityUnitBest forCost / caveat
By lineWhole lineCode, config, paragraph-level docsIntra-line tweaks show as delete+add of the whole line
By wordSpace/punctuation tokensEnglish prose, in-sentence doc editsChinese has no space tokens, needs segmentation first
By characterSingle characterSpotting typos, IDs, symbol driftVerbose; good for short strings, not long text
By glyphSingle CJK characterPrecise in-sentence CJK editsVery different from "by word" - see below

Note: For Chinese, "by character" and "by word" differ enormously. Chinese text has no spaces, so a character diff of "这是第一行。" to "这是修改后的第二行。" costs 5 edits (6 vs 10 glyphs, LCS edit distance 5 on that one line); if you segment first and diff by word, the shared prefix "这是" is kept and only "第一行 → 修改后的第二行" flags as changed, reporting far less. English is space-tokenized, so word vs character gaps are smaller (about 12 character edits for the same kind of change). For Chinese, picking the right granularity matters more than picking the algorithm. For long text, first check length with the Word Counter before deciding to split.

Similarity and difference ratio: three computable metrics

"How alike are the two versions" should not be a guess. The three metrics below are all reproducible by script; the numbers in this tool's examples come from the same formulas.

1) Levenshtein distance (edit distance): the minimum single-character insertions, deletions, and substitutions to turn one string into the other. Smaller means more similar.
2) Jaccard similarity: intersection over union of two sets, 0-1. For line sets, J = unchanged lines / (unchanged + added + deleted lines).
3) Normalized edit distance (similarity): Sim = 1 - Lev / max( len(A), len(B) ), shown as a percentage; closer to 100% means more similar.

Using the page default input (3-line original vs 4-line new): the whole-text character-level Levenshtein distance is 40 (English), normalized similarity about 66.9%; the line-set Jaccard is 40.0%. Note: the line counts do not match (3 vs 4 lines) which drags Jaccard down, while normalized edit distance only looks at total characters - so the two give different "how alike" conclusions. Review both.

MetricFormulaDefault inputRead
Levenshtein distancemin insert/delete/substitute40smaller = more similar
Jaccard (line set)unchanged / all lines seen40.0%hurt by line-count gap
Normalized edit distance1 - Lev / max(len)66.9%only counts characters

unified diff vs context diff, field by field

Command-line diff usually emits two classic formats. Knowing the fields lets you translate this tool's side-by-side result into a pasteable patch. Markdown docs can be tidied first in the Markdown Preview before comparing.

Fieldunified diff (@@ / + / -)context diff (* / ! / context)
File header--- a/file / +++ b/file mark old/new*** file1 / --- file2 two-column headers
Hunk header@@ -l,s +l,s @@ old/new start & length*************** separates the two context blocks
Unchanged linespace prefixspace prefix / context line
Added line+ prefix+ prefix
Deleted line- prefix- prefix
Context linesdefault 3 (use -U n)default 3 above and below

This tool's side-by-side view is equivalent to "aligning a unified diff's + / - lines left and right": the old version sits on the left (deleted lines land left, blanks fill gaps), the new version on the right (added lines land right). There is no file header because it compares two pasted texts, not disk files.

Difference-ratio benchmarks for common text pairs (measured)

The four samples below were run through this tool's own line-by-line LCS logic. Difference ratio is defined as "changed lines / (unchanged lines + changed lines) x 100%". They give you a直觉 gauge of "how alike is alike, how big is big". To move large text, shrink it first with the Compress/Decompress tool, then compare in segments.

Sample typeLines (old→new)UnchangedAddedDeletedTotal changedDiff ratio
Minor in-place edit (change 1 + add 1)12 → 131121321.4%
Local rewrite (change 4, keep 8)12 → 12844850.0%
Full rewrite (almost all new)12 → 120121224100.0%
Code with comments (change 2)8 → 8622440.0%

Note: The difference ratio only looks at line identity, not how many characters changed inside a line; editing one character and rewriting the whole line both count as "1 changed line" at the line level. To gauge intra-line magnitude, return to the character-level / glyph-level Levenshtein from the previous section.

Three real examples (page default input)

All three examples use the default content already in this tool's text boxes; the numbers match what you see after clicking "Compare".

Example 1: line-level diff stats for the default input
Original box (3 lines):
"Hello, welcome to the text diff tool!"
"This is the first line."
"Third line unchanged."
New box (4 lines):
"Hello, welcome to the text diff tool!"
"This is the modified second line."
"Third line unchanged."
"Fourth line is new content."
After LCS alignment: line 1 and line 3 are unchanged (2 lines), "This is the first line." is deleted (1 line), "This is the modified second line." and "Fourth line is new content." are added (2 lines). Stats: unchanged 2, added 2, deleted 1, total changed 3, difference ratio = 3 / (2+3) = 60.0%. In the side-by-side view only the area around line 2 and line 4 are highlighted; everything else stays white.

Example 2: the changed line at character granularity
Focus on the changed line: old "This is the first line." (23 chars) vs new "This is the modified second line." (33 chars). A character-level Levenshtein needs 12 edits (swap "first" for "modified", "line" for "second", and add "second"). If you switched to word granularity (English is space-tokenized), the shared prefix "This is the" is kept and only "first line" → "modified second line" flags - far less noise. This shows that for English, granularity still shapes readability, though less drastically than for Chinese. This tool compares by line; use the Word Counter to reason about intra-line change.

Example 3: overall similarity of the default input
Feed both full texts into the similarity formulas: character-level Levenshtein distance = 40, normalized similarity ≈ 66.9%; line-set Jaccard = 40.0%. One metric high (66.9%) and one low (40.0%) looks contradictory but is consistent - normalized edit distance only counts "how many characters changed", while Jaccard is dragged down by the "3 lines became 4" line gap. Conclusion: this text kept about two-thirds of its characters but changed four-tenths of its line structure.

Connecting to git diff / version control

Git uses Myers (and its variants, per Myers 1986) under the hood, plus rename detection and hunk merging. This tool relates to git diff in three layers: first, this tool is a file-less "mini diff" for quickly comparing two pasted snippets; second, to bring a result back into Git you should save the difference as a unified diff (see the field table above) so git apply can read it; third, Git's line numbers are file-global while this tool only gives relative positions, and conflict markers (<<<<<<< / ======= / >>>>>>>) must be resolved in Git. To tally change size, scan here first, then run git diff --stat for a repo-wide summary. For a deeper treatment see the blog post Text Diff in Practice.

Frequently asked questions

Which diff algorithm does this tool use, and why does it compare line by line?

It uses an LCS (Longest Common Subsequence) dynamic-programming pass, anchoring on identical lines and flagging lines present in only one side as added or deleted. Line-by-line comparison is simple and stable for prose, config, and documents. For heavily reordered code, Git's underlying Myers (1986) / Patience / Histogram strategies are better.

For Chinese text, does character-level or word-level diff show a bigger difference?

Much bigger. Chinese has no space-delimited words, so a character diff of "这是第一行。" to "这是修改后的第二行。" costs 5 edits, whereas word-segmented diff keeps the shared prefix "这是" and only flags "第一行 → 修改后的第二行". English is space-tokenized, so word vs character gaps are smaller (about 12 character edits for the same kind of change).

What is the difference between unified diff and context diff output?

Unified diff (the GNU diffutils default) puts old/new hunks in one column with @@ -l,s +l,s @@ headers and + / - prefixes; context diff separates old/new with *** and --- headers and marks changed lines with !. This tool's side-by-side view is equivalent to aligning a unified diff's + / - lines left/right.

How is the change rate (difference ratio) calculated?

Change rate = changed lines / (unchanged lines + changed lines) x 100%, where changed lines = added + deleted. It only looks at line identity, not how many characters changed within a line; for intra-line magnitude use character-level Levenshtein.

Can I feed this tool's output directly into git?

This tool is a file-less mini diff. To bring it back into Git, save the difference as a unified diff (with --- / +++ file headers and @@ hunks) so git apply can read it; conflict markers must be resolved in Git. After a quick scan here, run git diff --stat for a repo-wide summary.