File formats

Character Encoding Explained And Why Text Arrives Broken

The bytes are almost always fine. What broke is the agreement about how to read them.

9 min read

Character encoding is the table that turns bytes into letters. A file holds bytes. It does not hold letters. Turning bytes into letters needs a table saying which number means which character. A file rarely says which table it was written with. Every garbled name, every question mark where an accent should be, comes from that one gap.

This turns up wherever text moves between programs. A CSV that opens wrong in Excel, a subject line that arrives as symbols, a name with an accent that survives one system and not the next. The bytes are almost always fine. The agreement about reading them is what broke.

The Character Encoding Table Nobody Sends With the File

Start with what a byte can hold. One byte gives 256 possible values. English needs about a hundred characters, so the early agreement, ASCII, used half the range and left the rest unused.

That spare half became the problem. Every region filled it differently.

The byteUnder ASCIIUnder Windows-1252Under ISO 8859-7
0x41AAA
0x65eee
0xE9undefinede with an acute accenta Greek letter
0xF6undefinedo with an umlauta different Greek letter
The top two rows are why the problem hides for so long. Ordinary English is identical under every one of these, so a file looks perfect until the first name with an accent in it.

Nothing inside a plain text file names its encoding. There is nowhere to put one. A program opening it looks for a declaration somewhere outside the file. Failing that it guesses. Failing that it falls back to a regional default set years ago on a machine nobody remembers.

What Unicode Changed About Character Encoding

The Unicode Consortium broke the problem in two. Holding those halves apart clears up most of the confusion.

Unicode, the List

  • Every character in every script
  • One number each, called a code point
  • The letter A is always 65
  • Says nothing about bytes

UTF-8 and UTF-16, the Ways to Write It

  • Turn each number into bytes
  • UTF-8 uses one to four per character
  • UTF-16 uses two or four
  • Same characters, different bytes
Unicode is not an encoding, which is why asking whether a file is Unicode gets you nowhere. The question that has an answer is which encoding of Unicode it uses.

UTF-8 won the web on one property. Plain English under UTF-8 is byte for byte identical to ASCII, so decades of existing text became valid UTF-8 without anybody touching it.

the word  cafe, with an accent on the e

ASCII        63 61 66 65 ??     the accent has no byte
Windows-1252 63 61 66 E9        one byte, meaning fixed by region
UTF-8        63 61 66 C3 A9     two bytes, meaning fixed everywhere

read the UTF-8 bytes as Windows-1252
             c  a  f  A-tilde  (c)
             cafA(c)          the classic wrong result

Why Garbled Text Looks the Way It Does

Mojibake is not random. It follows the tables exactly, which is why the same wrong pairs appear over and over.

What you seeWhat happened
A capital A with a tilde before a symbolUTF-8 read as Windows-1252
A black diamond with a question markThe program gave up and substituted
A single question mark where a letter wasConverted to an encoding with no room for it
Chinese or Cyrillic in an English documentA two byte encoding read as one byte. Or the reverse
Every other character is a blank boxEncoding is right, the font has no glyph

The last row is not an encoding problem at all. Boxes mean the text decoded correctly and the font has nothing to draw. Changing the encoding will not help. This distinction saves a great deal of wasted effort.

The diamond question mark is the one that cannot be undone. Every unreadable byte becomes that same character, so the original values are gone rather than misread. Everything else on this list is recoverable from the original file, which is the argument for never overwriting it.

Two Different Things Both Called Encoding

This is where the word does real damage, because the same term covers two problems that have nothing to do with each other.

Character encoding

What does this byte mean
UTF-8
Windows-1252
ISO 8859-1
UTF-16

decides which letter
  a byte stands for

Get this wrong and the wrong letters appear. The bytes are unchanged.

Transfer encoding

How do these bytes survive
base64
quoted-printable

decides how bytes cross
  a channel that only
  carries plain text

Get this wrong and you see a wall of characters rather than a file.

A message can use both at once. Most do. The body is UTF-8 text wrapped in quoted-printable. The attachment is arbitrary bytes wrapped in base64. Two layers, two jobs.

Mail keeps the two visible side by side. The transfer layer is why an attachment arrives a third larger than the file. The character layer is why a subject line in French sometimes arrives as symbols. MIME carries both declarations in the same header block.

Read next Why Email Attachments Are Encoded And What It Costs The other encoding. What it adds to everything you send.

Where a File Declares Which Character Encoding It Uses

Some formats declare it. Some cannot. Knowing which is which explains why certain files give trouble and others never do.

FormatDeclares its encoding
HTML and XMLYes, in a tag near the top
EmailYes, a charset on every text part
JSONUTF-8 by the specification, no declaration needed
Plain text and CSVNo. Nothing anywhere
Word and modern Office filesYes, inside the package
PDFYes, per font and per text object

CSV is the format that causes the most of this. It has no header, no declaration and no specification worth the name. Every program opening one has to guess. Excel falling back to a regional default is behind most spreadsheet trouble people meet.

The Byte Order Mark And Why It Divides People

Since a file cannot declare its encoding, somebody proposed marking the front of it instead. That is the byte order mark.

It works. It also creates a second problem. Software that expects content at byte zero now finds three unexpected ones. The results range from an invisible character at the start of a heading to a script that refuses to run.

  1. Windows tools Want itExcel in particular reads a UTF-8 CSV correctly when the mark is present and often wrongly when it is not
  2. Web and Unix tools Do not want itTreated as content, so it appears as a stray character or breaks a file that must start with something specific
  3. The practical rule Depends on the readerInclude it where a Microsoft program has to open the file. Leave it out everywhere else
There is no correct answer here, only a correct answer for a given reader. That is unusual and it is why the argument has never settled.

Reinterpreting Versus Converting And Why It Matters

Every editor that handles encodings offers two commands that sound alike. Choosing the wrong one is how a recoverable file becomes an unrecoverable one.

Reinterpret

Notepad++ calls this Encode in
bytes  unchanged
table  changed

read the same bytes
  against a different
  table

The one you want while diagnosing. Try a table, look at the result, try another. Nothing is written.

Convert

Notepad++ calls this Convert to
bytes  rewritten
table  changed

write new bytes for
  the characters
  currently on screen

Correct only once the text already reads properly. Run it on garbled text and the garbling is written into the file.

The order is the whole thing. Reinterpret until the text is right, then convert. Convert first and you have made the wrong reading permanent.

This is how files get genuinely damaged. Somebody opens a file that looks wrong and saves it as UTF-8 hoping that helps. The editor faithfully writes out the characters it was showing. The original byte values are gone. No later effort recovers them, which is the real reason for working on a copy.

When the Encoding Has Been Wrong Twice

Sometimes the garbling has been through the mill more than once. That shows.

correct        Federation, with an accent
once wrong     FA(c)deration
twice wrong    FAA(c)A(c)deration

Each pass takes the wrong characters and encodes those, so the damage compounds and the string grows every time. It is still reversible. It needs the same number of passes back that it took going forward.

Long runs of accented capitals are the signature. One or two odd characters where an accent belongs is a single misreading. A cluster of five or six is double encoding. It tells you the file passed through two systems that each guessed differently.

Working Out Which Character Encoding a File Uses

  1. Ask the editor what it thinks. Notepad++ shows the encoding in the status bar and VS Code in the bottom right corner. On Mac or Linux the file command reports it. That is a guess rather than a reading. It is still a better starting point than your own.
  2. Look at where the text goes wrong. Ordinary English fine and accents broken points at a one byte encoding read as UTF-8 or the reverse. Everything broken points at something more serious.
  3. Try UTF-8 first. It is the likeliest answer by a wide margin. Text coming out clean means you are finished.
  4. Then try the regional default. Windows-1252 for western European text. The matching code page for anything else. Between those two you have covered most files.
  5. Check the first three bytes. EF BB BF means a UTF-8 mark is present, which both tells you the encoding and explains a stray character at the start.
  6. Keep the original. Work on a copy every time. Once a program has written the diamond question mark into a file, no amount of later effort brings the characters back.

Automatic detection is a guess and the standard says so. It works by statistics rather than by reading a declaration, so it is right most of the time and confidently wrong the rest. Where a declaration exists, believe it over any detector.

Where the file in question is a mailbox rather than a spreadsheet, the encoding is declared per part and a reader that honours those declarations shows the text as intended. Our file viewers do that in a browser tab. The converters carry the declarations through rather than flattening everything to one guess.

Encoding behaviour and byte level examples checked against the Unicode standard and the referenced articles in August 2026.

Questions People Ask

7 questions, answered in full below.

Why does my file show question marks or odd symbols?

Because it was written under one agreement about what the bytes mean and opened under another. Nothing is damaged. The same bytes are being read against the wrong table, which is why the wrong characters appear in exactly the right places.

Is UTF-8 the same as Unicode?

No. The distinction is the useful one. Unicode is the list of characters and the number each one gets. UTF-8 is one way of turning those numbers into bytes. UTF-16 is another way of turning the same numbers into different bytes.

Why does Excel mangle my CSV?

Because a CSV carries no statement of its own encoding, so Excel has to guess and its guess is often a regional default rather than UTF-8. Saving as CSV UTF-8 rather than plain CSV usually settles it. So does opening through the import dialogue, where you can name the encoding yourself.

What is a BOM and should I use one?

A few bytes at the start declaring which encoding follows. It helps Windows tools guess correctly and it upsets a good deal of software that expects a file to begin with content. Use it where a Microsoft program has to read the file, avoid it elsewhere.

Can mojibake be reversed?

Often, since the original bytes usually survive. Where a program has already replaced unreadable bytes with the diamond question mark, the information is gone for good, because every failure becomes that same character. That is why keeping the original file matters more than fixing a copy.

Is base64 a character encoding?

No. The shared word causes real confusion. Base64 converts bytes into a small set of safe characters so they survive a journey. Character encoding decides what a byte means in the first place. Different problems, unrelated solutions.

What should I use for new files?

UTF-8, without exception worth arguing about. It covers every script, it is what the web overwhelmingly uses and plain English text comes out identical to ASCII. The only real question is whether a particular Microsoft program on the receiving end needs a BOM.

Sources

Where the figures and behaviour described above were checked.

  1. Character encoding Wikipedia
  2. Mojibake Wikipedia
  3. Charset detection Wikipedia