Damerau–Levenshtein distance calculator
form and from are 1 edit apart, because swapping two neighbouring letters counts as a single step, while kitten and sitting need 3. You also get a similarity score from 0 to 1, useful for catching typos and near-duplicate names. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Text a
- kitten
- Text b
- sitting
- Distance
- 3
- Len a
- 6
- Len b
- 7
- Max len
- 7
Damerau–Levenshtein distance is a classic edit metric that counts how many single-character operations turn one string into another when the allowed operations are insertion, deletion, substitution, and transposition of two adjacent characters. That last operation is what separates it from plain Levenshtein distance and makes it especially useful for real-world typos: people often swap two neighbouring keys (form versus from, teh versus the) and those should cost one step, not two substitutions. This capability implements the Optimal String Alignment form of the distance with a pure dynamic-programming table, so every pair of inputs yields the same integer on every runtime.
What Damerau–Levenshtein measures and how it differs from plain Levenshtein
Edit distance asks how many unit changes are needed to rewrite a source string as a target string. Classical Levenshtein allows three unit operations: insert one character, delete one character, or substitute one character for another. Each costs one.
Damerau’s extension adds a fourth operation: swap two adjacent characters for a single unit cost. That extension matches how people actually mistype words on a keyboard. For example, the strings ab and ba differ by one adjacent transposition under Damerau–Levenshtein and by two substitutions under plain Levenshtein.
Kitten versus sitting still costs three (as in the textbook Levenshtein example) because the cheapest path uses substitutions and an insertion rather than a single swap. OSA is the form most libraries label Damerau–Levenshtein for typo correction; it forbids applying two overlapping transpositions on the same substring, which keeps the metric simple and O(n·m) in time and space. Empty strings are valid: the distance from the empty string to any string is that string’s length, and the distance between two empty strings is zero.
Identical strings always yield distance zero and similarity one, including after optional case folding.
Where this distance proves useful
Product search and inventory tools use edit distance with transpositions to rank near-miss SKUs and brand names before falling back to slower semantic models. CRM and deduplication pipelines flag candidate duplicate rows when distance is at most one or two and similarity is above a fixed threshold, catching swapped letters that plain equality or even plain Levenshtein would under-score. Spell-check demos and classroom exercises need a deterministic oracle that marks form versus from as distance one and charges a transparent fixed fee rather than token cost.
Invalid input does not consume balance. Pair the integer distance with your own threshold policy—accept distance zero only for exact keys, distance one for aggressive typo fix, similarity above zero point eight for soft merge hints—and you get a small, auditable building block for fuzzy matching without standing up a full search engine or NLP stack of your own.
What you can do with it
Typo-tolerant product and SKU matching
Rank catalogue candidates when a shopper or supplier string is one swap or one edit away from the true SKU, without calling an embedding model.
CRM and record deduplication
Flag near-duplicate names and addresses where adjacent letter swaps are common, using a fixed distance or similarity threshold.
Homework and algorithm demos
Show students the OSA dynamic program on kitten/sitting and ab/ba so transposition cost is visible next to plain Levenshtein.
FAQ
What is Damerau–Levenshtein distance?
It is the minimum number of insertions, deletions, substitutions, and adjacent character transpositions needed to turn one string into another.
How does it differ from ordinary Levenshtein distance?
Plain Levenshtein has no transposition operation, so swapped neighbours cost two substitutions. Damerau–Levenshtein (OSA) counts an adjacent swap as one edit, which better matches real keyboard typos.
Are empty strings allowed?
Yes. Distance from empty to a non-empty string equals that string’s length; two empty strings have distance zero and similarity one.
What does the similarity score mean?
It is 1 minus the distance divided by the length of the longer text. Kitten and sitting are 3 edits apart and the longer word has 7 letters, so the similarity is about 0.571428571429. Identical texts score 1.
Does it tell capitals apart?
Yes, by default Kitten and kitten are one edit apart. Turn off case sensitivity and both texts are lowercased first, so differences in capitals no longer add to the distance.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/str/damerau-levenshtein \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"text_a":"kitten","text_b":"sitting"}'const res = await fetch("https://api.kit.forhosting.com/str/damerau-levenshtein", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"text_a": "kitten",
"text_b": "sitting"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/str/damerau-levenshtein",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"text_a": "kitten",
"text_b": "sitting"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/str/damerau-levenshtein", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"text_a":"kitten","text_b":"sitting"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"text_a":"kitten","text_b":"sitting"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/str/damerau-levenshtein", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"text_a": "kitten",
"text_b": "sitting"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "str.damerau_levenshtein",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
You send two texts and an optional case-sensitivity flag; you receive the distance, both lengths, a normalized similarity between zero and one, and a boolean identical flag. The free browser path and the prepaid API path share the same module, so homework checks, fuzzy-match thresholds, and production pipelines never disagree on whether two labels are close enough to merge.
What Damerau–Levenshtein measures and how it differs from plain Levenshtein
This endpoint uses the Optimal String Alignment (OSA) recurrence: a dynamic-programming matrix where cell (i, j) is the minimum of delete, insert, substitute-or-match, and—when the last two characters of each prefix are a crossed pair—transpose from cell (i−2, j−2).
Input contract, response fields, and validation rules
Each string is capped at five thousand characters so the quadratic table stays bounded on the free edge path. A short formula string documents the OSA recurrence for display next to the answer. Failed validation is not billed. Keep inputs short enough for interactive use, pin the integer distance and rounded similarity in tests, and you get reproducible fuzzy scores without a language model or external dictionary. POST a JSON body with two required string fields: text_a (aliases a, string1, s1, left, first, source) and text_b (aliases b, string2, s2, right, second, target). Both may be empty; missing or non-string values fail with invalid_input naming the field. Optional case_sensitive defaults to true so Kitten and kitten can differ; set it to false to lowercase both sides before the table is filled. On success the body echoes text_a, text_b, and case_sensitive; reports distance as a non-negative integer; reports len_a, len_b, and max_len for the normalized strings; reports similarity as (max_len − distance) / max_len rounded to twelve decimals (or one when both lengths are zero); and sets identical to true exactly when distance is zero. Example: text_a kitten and text_b sitting yields distance three, lengths six and seven, max_len seven, similarity about zero point five seven one, and identical false. Example: text_a ab and text_b ba yields distance one because of the adjacent swap.
Technical questions
Is the comparison case-sensitive?
By default yes (case_sensitive true). Set case_sensitive to false to lowercase both strings before computing the distance so Kitten and kitten match.
What does the Damerau–Levenshtein calculator cost?
The browser tool is free. API requests use prepaid KIT balance at $0.002 per successful call; invalid input is not billed.