From A to 😊: Mastering Character Encoding as a Beginner

Talks about artificial intelligence, building SaaS solutions, product management, personal finance, freelancing, business, system design, programming and tech career tips
Search for a command to run...

Talks about artificial intelligence, building SaaS solutions, product management, personal finance, freelancing, business, system design, programming and tech career tips
Introduction 
Making llms argue for answers to problems that confuse them

As someone who practically lives in their browser, I’ve spent years chasing the perfect browsing experience. I wanted a tool that’s sleek, powerful, and respects my time and privacy. After falling in love with Arc for its innovative features, I thoug...

The modern technique of image interaction with AI

Since you started coding, you’ve typed letters, numbers, even emojis—but how does your computer get it? The answer’s character encoding, the magic that turns “A,” “世,” or “😊” into binary. This guide takes you from ASCII’s baby steps to Unicode’s global domination, breaking it down for beginners.
Computers only speak numbers—binary 0s and 1s. Encoding is like a translator: it gives every character (letter, digit, symbol) a unique number that becomes binary. Example: “A” = 65 = 01000001. It’s the bridge between your code and the machine.
In the 1960s, ASCII (American Standard Code for Information Interchange) was born. It standardized text for early computers using:
Numbers 0–127
7 bits per character (often padded to 8)
It held 128 characters:
A–Z (uppercase)
a–z (lowercase)
0–9
Punctuation (. , ; : ' " ! ? ( ))
Control codes (like “enter” or “tab”)
Examples:
“A” = 65 = 01000001
“a” = 97 = 01100001
“1” = 49 = 00110001
ASCII is fixed-length—every character uses the same 7 bits. Think of it like this:
# ASCII in action
char = "A"
number = ord(char) # Returns 65
binary = bin(number) # "0b1000001"
print(binary[2:]) # "1000001" (7 bits)
Pros:
Simple to code
Easy to jump to any character (just count 7-bit chunks)
Fast to process
Cons:
Tiny 128-character limit
English-only—no “ñ” or “π”
Wastes space for small sets
As coding went global, ASCII flopped. With just 128 slots, it couldn’t handle:
Japanese (e.g., “こんにちは”)
Arabic (e.g., “مرحبا”)
Even French accents (e.g., “café”)
Workarounds popped up:
Latin-1: Western Europe (adds “é,” “ñ”)
Shift-JIS: Japanese
Big5: Chinese
But chaos hit. A Latin-1 file opened in Shift-JIS? Gibberish—like “ñ” turning into “ñ”. Emails between countries? Unreadable.
Unlike fixed-length (same bits for all), variable-length encoding uses fewer bits for common characters, more for rare ones. It’s like compression for text.
In English, “E” is common, “H” less so. Fixed-length (3 bits):
“E” = 000
“T” = 001
“H” = 010
“THE” = 001 010 000 (9 bits)
Variable-length:
“E” = 0 (short, it’s frequent)
“T” = 10
“H” = 110
“THE” = 10 110 0 (6 bits)
# Imagine this in code
text = "THE"
bits = {"T": "10", "H": "110", "E": "0"}
encoded = "".join(bits[c] for c in text)
print(encoded) # "101100"
This saves space and inspires modern encodings.
By the late ‘80s, coders dreamed big: one standard for all characters. Unicode delivers, assigning unique code points to 149,000+ characters across 150+ writing systems.
Examples:
“A” = U+0041
“世” (Chinese “world”) = U+4E16
“😊” = U+1F60A
# Unicode in Python
print(ord("A")) # 65
print(ord("世")) # 19990 (U+4E16 in decimal)
print(ord("😊")) # 128522 (U+1F60A)
Unicode sets the numbers; UTF (Unicode Transformation Format) turns them into binary. Here’s the lineup:
Fixed-length: 32 bits (4 bytes) per character
“A” = 00000000 00000000 00000000 01000001
Easy, but bloated—overkill for “A”
Mixes 16 bits (2 bytes) for common chars, 32 bits for rare ones
Better than UTF-32, but still bulky for English
Variable-length: 1–4 bytes
ASCII chars (0–127) = 1 byte
Others = 2, 3, or 4 bytes as needed
How It Scales:
ASCII (A–Z, 0–9): 1 byte
Greek, Arabic: 2 bytes
Chinese, Japanese: 3 bytes
Emojis, rare symbols: 4 bytes
# UTF-8 in action
text = "A世😊"
for char in text:
print(f"{char}: {char.encode('utf-8').hex()}") # Hex bytes
# A: 41 (1 byte)
# 世: e4b896 (3 bytes)
# 😊: f09f988a (4 bytes)
Why UTF-8 Rules:
Matches ASCII for 1-byte chars
Efficient for most text
Self-syncing (byte patterns like 10 mark boundaries)
Here’s how UTF-8 encodes:
1 Byte (0–127):
Format: 0xxxxxxx
“A” (65) = 01000001
2 Bytes (128–2047):
Format: 110xxxxx 10xxxxxx
“ñ” (241) = 11000011 10110001
3 Bytes (2048–65535):
Format: 1110xxxx 10xxxxxx 10xxxxxx
“世” (19990) = 11100100 10111000 10010110
4 Bytes (65536–1114111):
Format: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
“😊” (128522) = 11110000 10011111 10011000 10001010
Notice: First byte flags the length; extra bytes start with 10. No guesswork!
New to programming? Here’s why encoding clicks:
Debug: “ñ” shows as “ñ”? Encoding mismatch.
Web: Add <meta charset="UTF-8"> in HTML or text breaks.
Files: CSV imports fail if encodings clash.
Space: UTF-8 shrinks text vs. UTF-32.
Global Apps: “こんにちは” or “😍” works worldwide.
# Test it
text = "Hello, 世界!"
with open("test.txt", "w", encoding="utf-8") as f:
f.write(text)
# Wrong encoding? Garbage output.
ASCII gave us 128 chars in 7 bits. Unicode scales to 149,000+ with UTF-8’s 1–4 byte smarts. It’s the backbone of your strings, files, and web apps. Next time you code “Hello, 世界!”, you’ll know the bits making it tick.