Character Encoding Converter
Convert text between any pair of encodings. Inspect what each codepage sees in your bytes. Auto-fix mojibake — that classic Привет corruption when UTF-8 was read as Latin-1.
Привет, РјРёСЂ! Hello, world! дЅ еҐЅдё–з•Њ гЃ“г‚“гЃ«гЃЎгЃЇ
Learn More
Unicode and UTF-8 won. Every modern protocol file format database and programming language defaults to UTF-8 — and yet character-encoding bugs remain one of the top three categories of why is my text broken tickets in production. The reason is simple: the world's data wasn't all created in 2026. CSV exports from a Windows finance system are still Windows-1251 in Russia Windows-1250 in Poland Windows-1252 in the US and Western Europe. Email gateways still default to Latin-1 when no charset is declared. Database connection strings to MySQL servers older than 8.0 still default to latin1. ZIP archives created on Mac OS 9 still carry MacRoman filenames. The legacy encodings haven't died — they've just been pushed down into the long tail of old data we still have to read. When those legacy bytes meet a UTF-8-everywhere modern system three things go wrong. (1) The legacy bytes get accepted as if they were UTF-8 which mostly works for the ASCII subset but produces replacement character U+FFFD wherever a high byte appears. (2) The legacy bytes get accepted with the wrong codepage label — Win-1252 read as Win-1251 produces gibberish that looks Russian-ish but isn't actually translation. (3) UTF-8 bytes get RE-encoded as another encoding to satisfy a downstream system that wanted legacy bytes and now the original text is lost. This tool exists to make the byte-level reality visible: pick an input encoding pick an output encoding see exactly what bytes flow through and how each common codepage interprets them. Inspect mode is particularly useful when you have no idea what the source is — paste the bytes scan the column of decoded outputs find the one that looks like real text.
Mojibake (Japanese 文字化け character transformation ) is the technical term for text that has been encoded one way and decoded another. The Russian Cyrillic word Привет in UTF-8 is the 12-byte sequence D0 9F D1 80 D0 B8 D0 B2 D0 B5 D1 82. If those bytes are read by a system that thinks they are Windows-1252 the system sees the 12 single-byte characters Ð Ÿ Ñ € Ð ¸ Ð ² Ð µ Ñ ‚ and stores them as 12 corresponding Unicode codepoints. The string is now wrong — but it is wrong in a precise mechanical reversible way. Fix mojibake mode reverses the transformation. It takes the corrupted text encodes it back to bytes using the encoding the text was misinterpreted as (Windows-1252) and then decodes those bytes with the encoding the text was originally in (UTF-8). For the example above this produces the original Привет. The tricky part is that you usually don't know the original (read-as was) pair. The tool tries every common pair — UTF-8 read as Win-1252 (most common) UTF-8 read as Latin-1 UTF-8 read as KOI8-R Windows-1251 read as Win-1252 Win-1252 read as Mac Roman — scores each result by how much it looks like real text (high ratio of printable letters presence of Cyrillic / CJK glyphs absence of replacement character U+FFFD) and ranks the top 5. The best match is almost always correct in practice especially for the UTF-8-as-Win-1252 case which dominates real-world mojibake.
For new code: UTF-8 everywhere. The HTTP / HTML / JSON / XML / CSV / source-code stack all default to UTF-8 by spec the byte cost over Latin-1 is negligible for natural language (1.0-1.2x for most languages 2-3x for CJK which has no good alternative anyway) and you avoid the entire class of charset-bug tickets. UTF-16 has narrow legitimate uses: JavaScript and Java in-memory strings Windows internal APIs and a few file formats that locked in the choice decades ago. UTF-32 is essentially never the right choice for storage — fixed 4 bytes per character costs much more than UTF-8 for any text and 4 bytes is rarely the indexing primitive you actually need. For reading legacy data recognize the family. Russian: Win-1251 for Windows-era archives KOI8-R for Unix-era email and BBS dumps IBM866 for DOS-era files Mac Cyrillic for old Mac archives. Western European: Latin-1 (ISO-8859-1) is the IETF default but Win-1252 is what Microsoft actually emitted and most Latin-1 data in practice has Win-1252 quotes and dashes. Polish / Czech / Hungarian: Win-1250 or Latin-2 (ISO-8859-2). Greek: Win-1253. Turkish: Win-1254. Baltic: Win-1257. Asian: GBK and GB18030 for Simplified Chinese (mainland China) Big5 for Traditional Chinese (Taiwan Hong Kong) Shift_JIS for Japanese (esp. Windows / older websites) EUC-JP for Japanese Unix EUC-KR for Korean. ISO-2022-JP for Japanese email (legacy but still used). When you don't know paste into Inspect mode and read the column that produces sensible text.
Frequently asked questions
Mojibake ( character corruption in Japanese) happens when text encoded one way is read as another. The classic case: UTF-8 bytes for Привет are 12 bytes long; if a Windows app reads them as Windows-1252 it sees the literal characters Привет because each multi-byte UTF-8 sequence becomes 2-3 single-byte Win-1252 glyphs. The auto-fixer reverses this: re-encodes the corrupted text back to bytes using the encoding it was misread as (Win-1252) then decodes those bytes with the encoding it was originally in (UTF-8). The tool tries every common (read-as was) pair scores each output by how much it looks like real text (ratio of printable + alphabetic + Cyrillic / CJK characters) and ranks the top 5 candidates.
The Web Crypto Encoding API exposes a TextDecoder that handles 30+ encodings (every legacy Windows codepage KOI8-R/U Mac variants GBK Big5 Shift_JIS EUC-KR ISO-2022-JP and more) but only one TextEncoder which always emits UTF-8. For decode the platform does the work; for encode this package hand-rolls reverse tables for the single-byte encodings (Latin-1..16 Win-1250..1257 KOI8-R/U IBM866 Mac Roman Mac Cyrillic). Multi-byte legacy encoders (GBK Big5 Shift_JIS EUC-KR) are decode-only — encoding TO those would need 60-100 KB of tables that aren't worth shipping in a browser tool when the source-of-truth data is almost already UTF-8.
Three diagnoses in decreasing order of frequency. (1) The text was read with the wrong encoding — most often UTF-8 bytes interpreted as Windows-1252. Use the Fix mojibake mode. (2) The text was correctly decoded but is being rendered in a font that has no Cyrillic glyphs — your eyes see boxes or question marks but the codepoints in memory are correct. Check the page's font-family. (3) The text was correctly decoded then RE-ENCODED into an output encoding that doesn't have Cyrillic — Latin-1 / Windows-1252 fall back to '?' for everything outside their alphabet. The encoder warns by replacing unrepresentable codepoints with '?' and the Inspect mode shows you exactly what each encoding sees.
BOM (Byte Order Mark) is a 2-3 byte prefix that some encoders write to identify the file as Unicode and disambiguate UTF-16 byte order. UTF-8 BOM is 0xEF 0xBB 0xBF; UTF-16 LE is 0xFF 0xFE; UTF-16 BE is 0xFE 0xFF. Modern advice: never write a UTF-8 BOM. It causes more bugs than it solves — many parsers (JSON CSV shell scripts source code) choke on the BOM as if it were content. UTF-16 BOMs are required when the byte order isn't otherwise known but if you control both ends pick UTF-16 LE explicitly and skip the BOM. This tool does not write BOMs by default; if your input has one the decoder strips it.
Historical accident with permanent consequences. JavaScript was designed in 1995 alongside Java's UCS-2 (later UTF-16) string model. ECMAScript locked in the 16-bit code unit as the indexing primitive which means a.length === 1 but 𝕏.length === 2 (a single emoji or supplementary-plane character takes two UTF-16 code units called a surrogate pair). Iterating with for-of ( of + str) and using codePointAt() instead of charCodeAt() handles this correctly but a lot of older code uses.length and indexing assuming code-unit == codepoint which produces subtle bugs at the BMP boundary (codepoints above U+FFFF). When this tool reports chars it counts code-units; when it reports UTF-8 bytes it counts the bytes UTF-8 would need to encode the same string.
Yes in the 0x80-0x9F range. Latin-1 (ISO-8859-1) leaves 0x80-0x9F as control characters (mostly unused). Windows-1252 fills that range with printable characters: smart quotes ('' ) em / en dashes (— –) the euro sign (€) the bullet (•) the trademark (™) and a few accented Western letters. This is why pasting text from Microsoft Word into a Latin-1 system shows boxes or question marks where the smart quotes were — Word emitted Win-1252 the Latin-1 reader doesn't have those characters. HTTP without a charset declaration is supposed to default to Latin-1 but most browsers heuristically switch to Win-1252 when they detect 0x80-0x9F bytes which papers over the issue but introduces its own ambiguity. Always declare your charset.
Convert and Inspect are O(n) and run synchronously in your browser. 100 MB is at the edge of what's practical — text rendering and copy operations bog down beyond a few MB. For large files do the conversion server-side: iconv -f WINDOWS-1251 -t UTF-8 logfile.log > converted.log on Linux/macOS or Get-Content -Encoding default file.log | Out-File -Encoding utf8 fixed.log on PowerShell. This tool is for the mid-sized case (paste debug copy fix) and for inspecting unfamiliar bytes — for batch jobs use a CLI.
More in Data Utilities
Developer validators, formatters and generators for structured data and identifiers.