Remove Accents and Strip Diacritics: Turning café Into cafe
How to remove accents and strip diacritics from text using Unicode NFD normalization, why café becomes cafe, where it helps, and where it quietly hurts.
Remove Accents and Strip Diacritics: Turning café Into cafe
Accents are wonderful for humans and miserable for machines. A title like Crème Brûlée reads beautifully on a menu and then falls apart the moment it has to become a URL, a database key, or a filename on an older system. The fix is to remove the accents and leave the plain letters behind: café becomes cafe, naïve becomes naive, Müller becomes Muller. This post explains exactly how that conversion works, where you should use it, and the one place where it will burn you if you are not careful.
What a diacritic actually is
A diacritic is the little mark stacked on, under, or through a letter: the acute accent on é, the grave on è, the circumflex on ê, the tilde on ñ, the umlaut or dieresis on ü, the cedilla on ç. The base letter is the same Latin letter you already know; the mark changes how it is pronounced or which word it belongs to.
The trouble is that most systems treat an accented letter as a completely different character from its plain form. To a strict ASCII pipeline, é is not "e with a hat" — it is an alien byte sequence that may or may not survive the trip. Stripping the mark is how you bring the letter back into the ASCII fold.
How Unicode normalization splits the letter from the mark
Here is the concrete mechanism, and it is cleaner than most people expect.
In Unicode, a character like é can be stored two ways. It can be a single code point (U+00E9, "Latin small letter e with acute"), or it can be a plain e followed by a separate combining acute accent (U+0301). These two forms look identical on screen, but the second one is literally two pieces glued together.
Unicode NFD — Normalization Form Decomposed — guarantees the second form. Run any accented Latin text through NFD and every precomposed character splits into a base letter plus one or more combining marks. So NFD normalization splits an accented character into a base letter plus a combining mark, which means removing the combining marks leaves the plain ASCII letter behind. é becomes e the instant you delete the mark that was riding on it.
The combining marks all live in a tidy block, roughly U+0300 through U+036F. Once the text is decomposed, you delete every code point in that range and recompose what is left. The result is bare ASCII. That is the whole trick: decompose, drop the U+0300–U+036F marks, keep the letters. No giant lookup table of "é→e, è→e, ê→e, ë→e" — the normalization does the heavy lifting for you. The remove accents tool runs exactly this path in your browser, so nothing you paste is uploaded.
A worked example: Crème Brûlée
Let me walk one phrase all the way through, because seeing the steps makes it click.
Start with Crème Brûlée.
- NFD decomposes it. The è becomes
e+ combining grave (U+0300). The û becomesu+ combining circumflex (U+0302). The é becomese+ combining acute (U+0301). The unaccented letters pass through untouched. Internally the string is nowC r e◌̀ m e B r u◌̂ l e◌́ e, where each ◌ is a separate mark. - Delete every code point in U+0300–U+036F. The grave, the circumflex, and the acute all vanish.
- What remains is Creme Brulee — plain ASCII, ready to be lowercased and hyphenated into
creme-bruleefor a slug.
Five accented letters, zero of them needing a hand-written rule. The same pass turns Açaí Bowl into Acai Bowl and über_plan into uber_plan.
When I first wired a version of this into a publishing pipeline, I had been maintaining a hard-coded replacement map — a sprawling object of "á":"a", "à":"a", "â":"a" that I kept extending every time an author pasted a letter I had forgotten. The day I deleted the whole map and replaced it with text.normalize("NFD").replace(/[̀-ͯ]/g, "") was genuinely satisfying. Three thousand lines of brittle data became one line of intent, and it covered accents I had never even typed.
The letters that refuse to decompose
NFD is not magic, and this is the caveat that trips people up. Some characters are not "a base letter plus an accent" — they are their own indivisible glyphs, so NFD leaves them completely alone.
- German ß stays ß. It has no plain-letter skeleton to fall back to; by convention it expands to ss, so straße should become strasse.
- Nordic ø stays ø. The slash is baked into the glyph, not a combining mark, so you have to map it to o yourself.
- Polish ł stays ł, mapping to l. Croatian/Vietnamese đ stays đ, mapping to d.
- Ligatures like æ, œ, and þ do not split either; they expand to ae, oe, and th.
If all you do is decompose and strip marks, straße comes out as straße and quietly breaks your "pure ASCII" promise. A complete tool keeps a small second-pass map for exactly these glyphs and lets you toggle it on or off depending on whether you want true ASCII or a lighter touch. If you want to inspect what decomposes and what does not, a Unicode normalizer shows you the code points directly.
Where stripping accents earns its keep
Once your text is ASCII-clean, several long-standing headaches go away:
- URL slugs. Accented characters in a URL get percent-encoded into noise like
caf%C3%A9the moment they are copied and pasted. Strip first, then run the result through a slug generator, and Crème Brûlée lands as a clean, shareablecreme-brulee. - Accent-insensitive search. Normalize both the stored field and the user's query, and resume finally matches résumé, Munchen finally matches München. No fragile per-language rule set required.
- Legacy systems and filenames. Old ZIP tools, strict ASCII database columns, and some CI pipelines mangle accented filenames into garbage. Cleaning the names first means the upload, the download, and the link all agree on one safe spelling.
- Sorting and dedup. Accented letters sort unpredictably across locales, and "café" and "cafe" can be treated as two different entries. Folding accents before you sort or deduplicate makes the ordering stable.
The caveat worth repeating: it is lossy
Removing accents throws information away, and it cannot be undone. In French, résumé (the document) and resume (to continue) collapse into the same spelling. In languages where a diacritic distinguishes two genuinely different words, that distinction is simply gone after the strip.
So the rule I follow is blunt: never run this on text a human will read. Keep the accents in display copy, article bodies, names on a page. Use accent removal only on the machine-facing layer — slugs, search keys, identifiers, import columns — where ASCII is mandatory and the original accented text still lives somewhere safe. If you need to swap specific spellings rather than fold every mark, a find and replace text tool gives you that surgical control instead, and case converter handles the casing once the accents are gone.
Treat accent stripping as a one-way door into ASCII, keep the accented original as your source of truth, and it becomes one of those small utilities you reach for constantly without ever thinking about the Unicode plumbing underneath.
Made by Toolora · Updated 2026-06-13