Character encoding (UTF-8)

The agreement on which bytes mean which characters. UTF-8 covers every script and emoji; mismatch it and 'café' turns into 'café'.

why accents turn into question marksmojibake fixweird symbols instead of lettersblack diamond question markcharset utf-8encoding problememoji breaks my databasecharacter enconding

See it

Live demo coming soon

What it is

Unicode assigns every character in every script a number; an encoding decides how those numbers become bytes. UTF-8 is the one you want: one byte for ASCII (so old English-only files stay valid), up to four for everything else, covering Arabic, Hangul, Devanagari, and emoji in a single scheme. It is the default for the web, and 'pick an encoding' is not really a decision anymore, it is a checklist.

The checklist is the whole job, because the bytes have to survive every hop: the meta charset tag within the first kilobyte of your HTML head, the Content-Type response header, the files on disk, the database column, and the client connection charset. Miss one link and you get mojibake: UTF-8 bytes read as Latin-1, which is why 'café' shows up as 'café'. Diagnose by symptom: garbled-but-recognizable means a display-side mismatch and is recoverable. A replacement diamond (U+FFFD) means a decoder hit bytes it could not read as UTF-8, which is usually still a decoding fault with the original bytes intact underneath. The genuinely bad sign is a literal '?' already sitting in storage: that is a lossy conversion that already happened, and nothing brings it back.

Two classics. MySQL's 'utf8' is a three-byte impostor that cannot hold an emoji or many CJK characters; the real one is utf8mb4. And a JavaScript string's .length counts UTF-16 code units, so an emoji counts as 2 and a flag as 4, which is how naive truncation slices a character in half and leaves a replacement box behind. Use Intl.Segmenter when you need what a human would call a character.

Ask AI for it

Audit and fix character encoding end to end in this project so every script and emoji round-trips intact. Start by detecting which database and storage path this project actually uses, then enforce UTF-8 across every hop: <meta charset='utf-8'> as the first element in the head, responses sending Content-Type: text/html; charset=utf-8, source files saved as UTF-8 without a BOM, and the client connection charset. For MySQL that means utf8mb4 with a suitable supported collation, never the three-byte 'utf8'; for PostgreSQL, SQLite, or anything else, keep that engine's native Unicode configuration instead of importing MySQL settings that do not apply. Replace any length checks or truncation that use string.length with grapheme-aware logic via Intl.Segmenter, and add a test fixture containing accents, Arabic, Japanese, and a multi-codepoint emoji.

You might have meant

grapheme clusterunicode normalizationbidirectional textlocale

Go deeper