Accent and Diacritic Removal, Explained
After reading this you will know how Unicode splits an accented letter into parts, why dropping the accent usually leaves plain ASCII, and where that trick fails so completely that a lookup table is the only fix.
What accent removal actually does
Type café into the tool and you get back cafe. Type naïve and you get naive. Type Škoda and you get Skoda. The output is plain ASCII: the 128 characters that every system on earth agrees on.
The interesting part is that the tool does this without a giant translation dictionary. For most European text it uses one property built into Unicode itself: many accented letters are defined as a base letter plus a mark that sits on top. Remove the mark, keep the base, and you are done. The letters that do not work this way (ß, ø, æ, ł, đ, þ) are handled by a short explicit table, which this article covers in detail.
When to strip accents, and when not to
Stripping accents throws away information. Sometimes that is exactly what you want. Often it is a mistake.
Good uses share one trait: the target system cannot handle the marks, and a plain-letter approximation is better than a failure or a mangled byte sequence.
- Building a URL slug or a file name where
café-münchenshould becomecafe-munchen. - Generating a login, an email local part, or a database key from a display name.
- Making search forgiving so that a user typing
ZurichfindsZürich. - Feeding a legacy system that only accepts ASCII.
Bad uses share the opposite trait: the marks carry meaning that the reader needs.
Accents are not decoration in most languages. In French ou means "or" and où means "where". In Spanish año means "year" and ano means something you did not intend to print. Never strip accents from text a human will read as final copy. Strip them only for machine keys, matching, and fallback.
The mechanism: Unicode normalisation form NFD
Unicode often gives you two ways to write the same accented letter. The letter é can be a single code point, U+00E9 (LATIN SMALL LETTER E WITH ACUTE), or it can be two code points: U+0065 (the letter e) followed by U+0301 (COMBINING ACUTE ACCENT). Both display as é. They look identical on screen.
The Unicode standard defines four normalisation forms to reconcile these. The one that matters here is NFD, canonical decomposition. NFD rewrites every precomposed letter into its base plus its combining marks, in a defined order. This is specified in Unicode Standard Annex #15, "Unicode Normalization Forms".
The left side is the single precomposed character. The right side is the base letter U+0065 followed by the combining acute accent U+0301. After NFD, the combining mark is a separate code point that you can detect and delete.
Combining marks live in a known range. The main block, "Combining Diacritical Marks", runs from U+0300 to U+036F: 112 code points covering accents, tildes, cedillas, rings, and more. The stripping step is: run NFD, then remove every code point in that range (and a few related blocks), then you are left with base letters.
NFD is loss-free and reversible on its own. Applying NFD to café and then recomposing with NFC gives you café back exactly. The loss happens only when you delete the combining marks, which is a separate step the tool performs after NFD.
The letters NFD cannot reach
NFD works because the accent is stored as a separate concept from the letter. Some letters do not fit that model. To Unicode, they are simply distinct letters with no decomposition at all.
ø(U+00F8) is not "o with a stroke" in a way NFD can undo. It has no canonical decomposition. NFD leaves it unchanged.ß(U+00DF, German sharp s) is one letter that historically stands for two. There is no accent to remove.ł(U+0142, Polish barred l),đ(U+0111, Croatian d with stroke),æ(U+00E6), andþ(U+00FE, thorn) are all in the same situation.
For these the tool uses an explicit replacement table. The choices follow the transliteration each language community actually uses.
| Letter | Code point | Replacement | Reason |
|---|---|---|---|
ß | U+00DF | ss | German standard spelling |
ø | U+00F8 | o | Danish/Norwegian usage |
æ | U+00E6 | ae | Historic ligature of a and e |
đ | U+0111 | d | Croatian/Vietnamese |
ł | U+0142 | l | Polish |
þ | U+00FE | th | Icelandic thorn |
Notice that some replacements grow the string. ß becomes two characters, æ becomes two, þ becomes two. Output length is not always equal to input length. That matters if you are padding fields to a fixed width.
Worked example: café, naïve, Škoda
Take the three demo strings and trace every character through the two stages: NFD, then mark removal (with table lookups where needed).
- café is 4 characters:
c,a,f,é. Onlyéchanges. NFD turnséintoe+U+0301, giving 5 code points. Removing the one combining mark leavesc a f e, which iscafe, 4 characters. - naïve is 5 characters:
n,a,ï,v,e. Theï(U+00EF, i with diaeresis) decomposes toi+U+0308(combining diaeresis). Remove the mark and you havenaive, 5 characters. - Škoda is 5 characters:
Š,k,o,d,a. TheŠ(U+0160, S with caron) decomposes toS+U+030C(combining caron). Remove the mark and you haveSkoda, 5 characters.
All three succeeded through NFD alone. No table lookup was needed. Now compare a fourth string, straße, 6 characters. NFD leaves it unchanged because ß has no decomposition. The table then replaces ß with ss, producing strasse, 7 characters. The output is one character longer than the input.
Try it: watch a letter split and collapse
The widget below lets you pick a letter and see all three representations side by side: the precomposed form, the NFD-decomposed form with the mark shown as a separate box, and the final ASCII result.
Reading the output and its limits
The tool answers exactly one question: what is the closest plain-ASCII spelling of this text under NFD plus a small table? It does not transliterate between writing systems.
- Diacritic removal
- Dropping marks from Latin letters so
résumébecomesresume. This tool does this. - Transliteration
- Converting one script to another by sound, so Russian
МоскваbecomesMoskva. This tool does not do this in general; it only handles the short Latin table above. - Case folding
- Normalising upper and lower case for comparison. Separate concern; use the case converter for that.
Because the scope is Latin-based, text in Greek, Cyrillic, Arabic, Hebrew, or CJK passes through almost unchanged. A Cyrillic й does carry a combining breve after NFD, so its mark is dropped, but the base letter stays Cyrillic. The result is not ASCII. Do not expect romanisation.
Common mistakes
Assuming output length equals input length. As the worked example showed, ß to ss and æ to ae add a character each. A name field capped at 20 characters can overflow after stripping.
Stripping first, comparing later, on unnormalised input. If one string uses precomposed é (U+00E9) and another uses decomposed e + U+0301, they look identical but are different byte sequences. Both strip to e here because NFD runs first, so this tool is safe. If you write your own stripper without NFD, the two forms behave differently.
Expecting semantic preservation. Turkish dotless ı and dotted i are different letters. German ö sorts near o in one standard and near oe in another. Stripping erases these distinctions. Use stripped text as a key or a fallback, never as the authoritative form.
If you need both, keep the original text for display and store the stripped version in a separate field for search and sorting. Do not overwrite the accented original.
Related tools
Accent stripping is one step in a cleanup pipeline. After you have plain ASCII, you often want to reshape it. Change capitalisation with the Case Converter, for example to build a lowercase slug. Remove or sort the resulting lines with Line Tools: Dedupe, Sort & Shuffle, which is handy when stripping collapses several spellings onto one key. If you need targeted substitutions the built-in table does not cover, Find & Replace with Regex lets you define your own. To fit stripped names into fixed-width fields, use Truncate, Pad & Wrap.
Frequently asked questions
Does removing accents change the length of my text?
Usually no, but not always. Every letter that decomposes under NFD (é, ï, Š, ñ) maps to one base letter, so length is unchanged. Table letters can grow: ß becomes ss, æ becomes ae, þ becomes th. The word straße (6 characters) becomes strasse (7 characters).
Why is ß turned into ss instead of just s?
Because ß stands for a doubled s sound, and German itself spells it ss when the sharp-s character is unavailable. This is the official fallback, so the tool follows it. It is a table choice, not an NFD result, since ß has no decomposition.
Will this convert Russian or Greek to the Latin alphabet?
No. The tool removes combining marks and applies a small Latin-letter table. It does not romanise other scripts. Cyrillic and Greek text keep their own letters; only their combining marks are dropped.
Is é as one character treated the same as e plus a combining accent?
Yes. The tool runs NFD first, which converts the single character U+00E9 into e + U+0301. From that point both inputs are identical, and both strip to e.
Can I reverse the operation to get my accents back?
No. Deleting the marks is lossy. From cafe there is no way to know whether the original was café, cafè, or cafe. Keep the original text if you need it.