Why does my text show weird characters like é?

CS Fundamentals 2 min read
Short answer

You are seeing UTF-8 bytes interpreted with a single-byte encoding. Declare UTF-8 everywhere — file, database, connection and HTTP header — rather than trying to repair the characters.

é in UTF-8 is two bytes: C3 A9. Read as Latin-1, those two bytes are à and © — hence é. The data is fine; the interpretation is wrong.

#Declare UTF-8 at every layer

HTML:

html
<meta charset="utf-8">

HTTP header (this wins over the meta tag):

text
Content-Type: text/html; charset=utf-8

Python:

python
open(path, encoding="utf-8")

Without it, Python uses a platform default — often cp1252 on Windows. This is the classic "works on my machine" encoding bug.

MySQL: use utf8mb4, not utf8.

sql
ALTER DATABASE app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

MySQL's utf8 is a historical mistake — it only stores three bytes per character, so emoji and some CJK characters fail. utf8mb4 is real UTF-8. Set the connection charset too:

php
new PDO('mysql:host=localhost;dbname=app;charset=utf8mb4', …);

#Question marks instead of mojibake

? or \ufffd means the data was already lost in a conversion — the bytes are gone. Fix the pipeline, then re-import the source.

#Characters are not bytes

python
len("café")            # 4 characters
len("café".encode())   # 5 bytes

Truncating a UTF-8 string by bytes can split a character in half. Slice by characters, or use a library that understands grapheme clusters — some emoji are several code points that render as one symbol.