Character-level diff

Character diff compares two strings position by position, one codepoint at a time. Paste both into the input pane separated by a line of ---; matching characters pass through, differing ones are wrapped in [-A|B-]. The compare runs in your browser; nothing uploads. For coarser views see word diff or line diff.

Input
Line 1:1 LF cloud_done Saved locally
Result Character-Level Diff
0 lines 0 chars

Position-based codepoint compare

Character diff is the finest-grained comparison in this hub. The split between text A and text B is a line containing exactly ---. The tool walks both strings in parallel; for every index i it checks whether A[i] equals B[i]. If the characters match, the character is appended to the output. If they differ, the pair is wrapped [-A[i]|B[i]-].

Comparison is position-based, not LCS. Inserting a single character at the start of B will mark every subsequent character as a change because the indices have shifted by one. Use Levenshtein distance to get the minimum edit count, or longest common substring to find the largest matching block.

String length asymmetry is handled by treating missing characters as empty strings, so the longer side's tail is emitted as a series of [-|extra-] or [-extra|-] markers. Comparison is case sensitive and treats whitespace as content; a tab in A versus a space in B produces a marker.

How to use character-level diff

  1. 1Paste string A into the input panel, then a line with ---, then string B.
  2. 2The character diff appears in the output panel with [-A|B-] markers on differing positions.
  3. 3Click Copy to copy the marked-up string, or Download to save it.
  4. 4For an edit count rather than a marked-up view, switch to Levenshtein distance.
  5. 5For the largest unbroken matching span use longest common substring.

Keyboard shortcuts

Drive TextResult without touching the mouse.

Shortcut Action
Ctrl FOpen the find & replace panel inside the input Plus
Ctrl ZUndo the last input change
Ctrl Shift ZRedo
Ctrl Shift EnterToggle fullscreen focus on the editor Plus
EscClose find & replace, or exit fullscreen
Ctrl KOpen the command palette to jump to any tool Plus
Ctrl SSave current workflow draft Plus
Ctrl PRun a saved workflow Plus

How the character diff works

Position-based equality

For each index i the tool checks A[i] === B[i]. No alignment heuristic, no LCS. Inserting a single character cascades as a long string of changes.

Inline marker for differences

Differing characters are wrapped [-A[i]|B[i]-]. The marker is plain ASCII, easy to read and easy to paste into a chat or a review.

Case and whitespace sensitive

A versus a registers as a change. Tabs, spaces, and line breaks all count as content and are compared like any other character.

Unequal lengths handled

When one side is longer, missing positions on the shorter side are treated as empty strings; the tail emits [-extra|-] or [-|extra-] markers depending on direction.

Three-hyphen separator

The split between A and B is a line containing exactly ---. The tool requires this marker to know where A ends and B begins.

Worked example

Position 0 differs (k vs s), itt matches, position 4 differs (e vs i), then n matches and g trails on B. For a single edit-count number, see Levenshtein distance.

Input
kitten
---
sitting
Output
[-k|s-]itt[-e|i-]n[-|g-][-|-]

Settings reference

Behaviour Effect on output
Separator A line containing exactly --- splits text A from text B.
Granularity Per character (per UTF-16 code unit, the JavaScript default).
Match rule Exact equality on each codepoint, including case.
Output for matches Character emitted as-is.
Output for changes Wrapped [-A-char|B-char-].
Unequal lengths Tail emitted with empty placeholder on the missing side.
Missing separator Output prompts for two halves split by ---.

FAQ

Why does an inserted character mark the rest of the string?
Comparison is position-based. Inserting a character at index i shifts everything to its right by one position, so they all stop matching their counterparts. For an alignment-aware view use longest common substring or count edits with Levenshtein.
How are surrogate pairs and emoji handled?
The tool indexes by UTF-16 code unit, the JavaScript default. Astral codepoints (most emoji and some CJK extension characters) occupy two units and may report partial differences if only one half misaligns. Normalise to NFC first if you see odd splits.
Are tabs and spaces compared?
Yes. Whitespace counts as content. \t versus   (a regular space) produces a marker.
How is this different from word diff?
Word diff tokenises on whitespace and compares whole words. Character diff compares every codepoint, including spaces and punctuation. Use word diff for prose, character diff for codes, hashes, and short strings.
Where does my text go?
Nowhere. Everything happens locally in your browser.