PoppyOS

Home › Guides

Why accented letters look garbled when you open a CSV in Excel (and the fix)

You open a CSV and Café appears as Café, or Japanese or Cyrillic text turns into question marks and boxes. The file is not corrupted. Excel read UTF-8 text as if it were an older single-byte encoding, because nothing in a plain CSV says which encoding it uses.

What is happening, in one example

In UTF-8, é is stored as two bytes. A program that assumes a legacy Windows code page (such as Windows-1252) reads each byte as its own character:

text = "Café,Zoë"
raw = text.encode("utf-8")
print(raw)
print(raw.decode("cp1252"))
b'Caf\xc3\xa9,Zo\xc3\xab'
Café,Zoë

That second line is what an app that guesses wrongly shows you. The data is intact; only the reading is wrong. This is why "just re-saving" a damaged file in Excel can make things worse: it saves the wrong characters for good.

Fix 1: open the file with the right encoding

  1. In a blank workbook choose Data › From Text/CSV and pick the file.
  2. Set File Origin to 65001: Unicode (UTF-8). The preview should now show the right letters.
  3. Choose Load.

Menu names are from current Microsoft 365 Excel; we have not tested every version.

Fix 2: save the file with a byte-order mark (BOM)

If you create the CSV yourself, or you can re-save it, a BOM at the start of the file is a three-byte signature that tells Excel the file is UTF-8, so a plain double-click works. In Python, use the utf-8-sig encoding when writing, and check what you got:

import csv

with open("cafe.csv", newline="", encoding="utf-8") as f:
    rows = list(csv.reader(f))

with open("cafe-excel.csv", "w", newline="", encoding="utf-8-sig") as f:
    csv.writer(f).writerows(rows)

print(open("cafe-excel.csv", "rb").read(3))
print(open("cafe-excel.csv", encoding="utf-8-sig").read().strip())
b'\xef\xbb\xbf'
Name,City
Zoë,Café Row

The first line shows the BOM bytes (EF BB BF); the second shows that the text reads back correctly. Editors such as Notepad, and "Save As › CSV UTF-8" in Excel, also write a BOM.

The downside of a BOM

Some programs do not expect it and show it as an invisible character glued to the first column name (a header that looks like Name but does not equal "Name"). In Python, reading with encoding="utf-8-sig" removes it safely whether or not it is present, which is why the scripts in our other guides always use it. So: write files meant for Excel with a BOM, and files meant for databases and scripts without one.

Tell if a file is UTF-8 at all

If the file was exported from an older Windows program it may really be in Windows-1252, and then UTF-8 is the wrong thing to select. A quick test is to try to read it as UTF-8 and see whether Python complains:

for name, data in [("utf-8 file", "Café".encode("utf-8")), ("windows-1252 file", "Café".encode("cp1252"))]:
    try:
        data.decode("utf-8")
        print(name, "-> valid UTF-8")
    except UnicodeDecodeError:
        print(name, "-> not UTF-8, try cp1252")
utf-8 file -> valid UTF-8
windows-1252 file -> not UTF-8, try cp1252

This is a heuristic, not proof: a short file of plain ASCII is valid in both, and that is fine, because it reads the same in both.

Last updated 2026-10-27. Code on this page was run on that date and the output shown is the real output. Spreadsheet menu steps are written from Microsoft's and Google's documented behaviour; where we have not run something ourselves, the page says so.

More guides

All guides