Visualize how text characters are represented as numerical codes in computers.
Overview
What is ASCII?
ASCII, which stands for American Standard Code for Information Interchange, is a character encoding standard. In simple terms, it's a universal dictionary that assigns a unique number to every letter, digit, and symbol you can type. Computers don't understand letters like 'A' or 'b'; they only understand numbers. ASCII translates our human-readable characters into a numerical format.
Character Representations
0 CHARS
Enter text to see ASCII codes
List ScrollVIEW
Tip: ASCII encodes 128 specified characters into 7-bit integers.
Understanding ASCII: The Language of Computers
Explore how every character you type is converted into a universal numerical code that computers can understand.
How It Works: From Character to Code
The standard ASCII table contains 128 unique codes, numbered from 0 to 127. Each code represents a specific character. For example:
The character 'A' is assigned the ASCII code 65.
The character 'a' is assigned the ASCII code 97.
The digit '5' is assigned the ASCII code 53.
A space character ' ' is assigned the ASCII code 32.
When you type "Hello", the computer sees the sequence of numbers: 72, 101, 108, 108, 111.
Characters as numbers
Computers store numbers. ASCII was the agreement, from 1963, about which number means which character — 128 codes covering the English alphabet, digits, punctuation and control characters.
Character
Decimal
Hex
NUL
0
00
\n (newline)
10
0A
space
32
20
0
48
30
A
65
41
Z
90
5A
a
97
61
z
122
7A
Three of those ranges are worth memorising because they make arithmetic tricks possible.
Digits start at 48, so ord('7') - ord('0') gives 7 — converting a character to its numeric value without a lookup table.
Uppercase starts at 65 and lowercase at 97, exactly 32 apart. So chr(ord('A') + 32) is 'a', and since 32 is a single bit (2⁵), case conversion is a bit flip — which is why it was historically so cheap.
Letters are contiguous, so 'a' <= c <= 'z' tests for a lowercase letter, and sorting strings by code point sorts alphabetically within a case.
That last line is a real source of surprise: sorting a list of names puts every capitalised entry before every lowercase one, because 'Z' (90) is less than 'a' (97).
Why 128 was not enough
ASCII covers English. It has no é, no ñ, no ö, no Cyrillic, no Greek, no Arabic, no Chinese, no emoji.
Unicode is the modern answer: one code point per character, covering every script, currently over 149,000 assigned. é is U+00E9, 中 is U+4E2D, and 🎉 is U+1F389.
Unicode assigns numbers; it does not say how to store them. That is what an encoding does, and UTF-8 is the one that won:
Character
Code point
UTF-8 bytes
A
U+0041
1 byte: 41
é
U+00E9
2 bytes: C3 A9
中
U+4E2D
3 bytes: E4 B8 AD
🎉
U+1F389
4 bytes: F0 9F 8E 89
UTF-8's decisive property is that the first 128 code points encode as single bytes identical to ASCII. Every ASCII file is already valid UTF-8, which is why adoption was possible at all.
Where this matters in NLP
Characters are not bytes.len("café") is 4 characters and 5 UTF-8 bytes. Truncating a string at a byte boundary can split a character in half and produce invalid data — a real bug when enforcing length limits on user input.
The same text can have two encodings. "é" may be one code point (U+00E9) or two (e + combining accent U+0301). They look identical and compare as different strings, which is the most common cause of "these records should match and do not". unicodedata.normalize("NFKC", text) resolves it, and should be the first step of any text pipeline.
Tokenisers work on bytes or characters. Byte-level BPE, used by GPT models, operates on UTF-8 bytes, so it can represent any text at all — at the cost of more tokens for non-Latin scripts, since each character consumes several bytes.
Encoding errors are silent or fatal. Reading a UTF-8 file as Latin-1 succeeds and produces mojibake; reading a Latin-1 file as UTF-8 raises UnicodeDecodeError. Always specify the encoding explicitly.
Before any of it is text, it is numbers
Every string is bytes, and the mapping from bytes to characters is where a surprising amount of NLP goes wrong. ASCII, Unicode and UTF-8 are all inspected here directly.
example_01.pyNumPy
import unicodedata
print("ASCII assigns a number to 128 characters. that is the whole standard:")
print("%10s %10s %10s %s" % ("char", "decimal", "hex", "binary"))
for ch in "A a 0 ~".split() + [" "]:
c = ch if ch != " " else " "
print("%10s %10d %10s %s"
% (repr(c), ord(c), hex(ord(c)), format(ord(c), "08b")))
print()
print("the ranges worth remembering:")
for lo, hi, what in ((48, 57, "digits 0-9"), (65, 90, "uppercase A-Z"),
(97, 122, "lowercase a-z"), (0, 31, "control codes")):
print(" %3d to %3d %s" % (lo, hi, what))
print()
print("uppercase and lowercase are exactly %d apart, which is one bit:"
% (ord("a") - ord("A")))
for ch in "AaZz":
print(" %s = %3d = %s" % (ch, ord(ch), format(ord(ch), "08b")))
print(" flipping bit 5 changes the case. that is why the old trick")
print(" 'ord(c) ^ 32' works, and why it breaks the moment you leave ASCII.")
print()
print("UNICODE assigns a number to every character in every script --")
print("about 150,000 of them so far:")
samples = ["A", "e", "é", "中", "ا", "€", "\U0001F600"]
print("%10s %12s %10s %s" % ("char", "code point", "name", ""))
for ch in samples:
try:
name = unicodedata.name(ch)
except ValueError:
name = "?"
print("%10s %12s %s" % (repr(ch), "U+%04X" % ord(ch), name[:40]))
print()
print("UTF-8 encodes those numbers as bytes, using a variable number:")
print("%10s %12s %8s %s" % ("char", "code point", "bytes", "the actual bytes"))
for ch in samples:
b = ch.encode("utf-8")
print("%10s %12s %8d %s"
% (repr(ch), "U+%04X" % ord(ch), len(b), " ".join("%02x" % x for x in b)))
print()
print(" ASCII characters are 1 byte and unchanged -- UTF-8 was designed to")
print(" be backward compatible, which is most of why it won.")
print(" everything else is 2 to 4 bytes.")
print()
print("SO len() DEPENDS ON WHAT YOU ARE COUNTING:")
for s in ("hello", "café", "中文", "\U0001F600"):
print(" %-8s characters %d, utf-8 bytes %d"
% (repr(s), len(s), len(s.encode("utf-8"))))
print(" a length limit measured in bytes is not a length limit measured")
print(" in characters, and neither is a length limit measured in tokens.")
print()
print("THE TRAP THAT BITES EVERYONE. the same visible character can be")
print("stored two different ways:")
a = "café" # e-acute as one code point
b = "café" # e followed by a combining accent
print(" %r -> %d chars, code points %s"
% (a, len(a), [hex(ord(c)) for c in a]))
print(" %r -> %d chars, code points %s"
% (b, len(b), [hex(ord(c)) for c in b]))
print(" they look identical. a == b is %s." % (a == b))
print(" normalise first and they agree: %s"
% (unicodedata.normalize("NFC", a) == unicodedata.normalize("NFC", b)))
print(" this is why every text pipeline should start with a unicode")
print(" normalisation step. two spellings of one word become two")
print(" vocabulary entries otherwise, and only one of them ever trains.")
print()
print("AND WHY MODELS WORK ON BYTES. a byte-level tokeniser has a")
print("vocabulary of exactly 256 and can represent any text ever written:")
text = "hello 中文 \U0001F600"
raw = text.encode("utf-8")
print(" %r" % text)
print(" as bytes: %s" % " ".join("%02x" % x for x in raw))
print(" %d bytes, every one of them in 0..255. no unknown characters are"
% len(raw))
print(" possible, in any language, ever.")
print()
print(" the cost is length. GPT-style models run byte-pair encoding ON TOP")
print(" of bytes -- merging common byte sequences into single tokens -- so")
print(" they get the coverage of bytes with something closer to the")
print(" sequence length of words. that is what 'byte-level BPE' means, and")
print(" it is why a model can handle an emoji it has never seen without")
print(" any special case at all.")
Output
Try it yourself
Use the "ASCII Code Explorer" above to see this process in action:
Type Your Name: In the "Input Text" box, type your name. Notice how each character, including the space, instantly appears in the "Character Representations" area with its corresponding Decimal, Hexadecimal, and Binary codes.
Case Sensitivity: Type the letter 'P' and then 'p'. Observe their ASCII codes (80 and 112). This difference is why passwords are often case-sensitive. Computers see 'P' and 'p' as completely different characters.
Numbers vs. Digits: Type the number '9'. Its ASCII code is 57. This is different from the numerical value 9. The character '9' is text, just like 'A' or '$'.
Special Characters: Try typing symbols like '@', '#', or '!'. Each has its own unique code, allowing for complex text and programming syntax.
Check the Statistics: The stats panel shows you the total characters and bytes. In standard ASCII, one character takes up one byte (8 bits) of memory.
Why is ASCII Important in NLP?
ASCII is a foundational concept in Natural Language Processing (NLP). While modern systems often use more advanced encodings like UTF-8 to support emojis and multiple languages, the core principle remains the same: text must be converted to numbers for a machine to process it. Understanding ASCII helps you grasp fundamental NLP tasks:
Text Normalization: Converting all text to lowercase (e.g., changing 'A' (65) to 'a' (97)) is a common preprocessing step to ensure words like "The" and "the" are treated as the same.
Feature Engineering: The numerical representation of characters can be used as features for machine learning models to identify patterns.
Data Cleaning: Identifying and removing non-ASCII characters can be crucial when working with datasets that should only contain standard English text.
In one line
ASCII is the essential bridge between human language and computer processing. It standardizes the representation of text as numbers, a fundamental step for all digital communication and computation. By interacting with the explorer, you can build a solid intuition for this cornerstone of computer science and NLP.
Practical handling
# always specify the encoding
with open("data.txt", encoding="utf-8") as f:
text = f.read()
# be explicit about failures
text = raw_bytes.decode("utf-8", errors="replace") # bad bytes become U+FFFD
text = raw_bytes.decode("utf-8", errors="ignore") # bad bytes dropped
# normalise before comparing
import unicodedata
a = unicodedata.normalize("NFKC", a)
b = unicodedata.normalize("NFKC", b)
a == b
Python 3 keeps this straight by separating the two types: str is a sequence of Unicode code points, bytes is a sequence of 8-bit values. You cannot concatenate them, which prevents a whole class of bug that Python 2 permitted.
The four normalisation forms: NFC composes characters where possible, NFD decomposes them, and NFKC/NFKD additionally fold compatibility variants (full-width characters, ligatures, superscripts). NFKC is the usual choice for text processing, because it collapses the largest number of visually-equivalent forms.
Other things worth knowing
Control characters occupy codes 0–31 and 127. Most are historical — bell, form feed, device control — and their presence in scraped text usually indicates a problem. Strip them.
Line endings differ. Unix uses \n (10), Windows uses \r\n (13, 10). Reading in text mode normalises them; reading in binary mode does not, and stray \r characters at line ends are a common annoyance.
Zero-width and invisible characters exist and cause trouble: zero-width space (U+200B), zero-width joiner, byte-order mark (U+FEFF). A BOM at the start of a file appears as an invisible character in the first field, which breaks header parsing in CSV files — encoding="utf-8-sig" strips it.
Emoji are often several code points. A single visible emoji may combine a base character, a skin-tone modifier and a zero-width joiner, so len() on an emoji string rarely matches what the user sees.
Questions people ask
Is ASCII still relevant? As a subset of UTF-8, yes — and never as a complete encoding for real-world text.
Why is 'A' < 'a'? Because 65 < 97. Sorting by code point puts all uppercase before all lowercase.
Should I always use UTF-8? Yes, for output. For input, detect or be told; chardet guesses when nothing else is available.
Why does my string length look wrong? Characters, bytes and user-perceived characters are three different counts. Emoji and combining accents make them diverge.
What is a byte-order mark? An invisible marker at the start of a file indicating the encoding. Harmless in principle, and it corrupts the first field of a CSV; use utf-8-sig to strip it.
Recap in one screen
ASCII maps 128 characters to numbers; digits at 48, uppercase at 65, lowercase at 97.
The 32-place gap between cases makes case conversion a single bit flip.
Unicode assigns code points for every script; UTF-8 stores them, with ASCII as a compatible subset.
Characters, code points and bytes are three different counts — truncate on the right one.
Normalise with NFKC before comparing anything, and always state the encoding when reading files.
Recall check
0 of 3
Say the answer out loud before you reveal it — recalling it is what makes it stick, and rereading it is not.
Without scrolling back — what is the one-line takeaway from this module?
ASCII is the essential bridge between human language and computer processing. It standardizes the representation of text as numbers, a fundamental step for all digital communication and computation. By interacting with the explorer, you can build a solid intuition for this cornerstone of computer science and NLP.
What does this module say about “What is ASCII”?
ASCII, which stands for American Standard Code for Information Interchange , is a character encoding standard. In simple terms, it's a universal dictionary that assigns a unique number to every letter, digit, and symbol you can type. Computers don't understand letters like 'A' or 'b'; they only understand numbers. ASCII translates our human-readable characters into a numerical format.
What does this module say about “How It Works: From Character to Code”?
The standard ASCII table contains 128 unique codes, numbered from 0 to 127. Each code represents a specific character. For example:
Cheat sheet
ASCII Character Codes
ASCII, which stands for American Standard Code for Information Interchange, is a character encoding standard. In simple terms, it's a universal dictionary that assigns a unique number to every letter, digit, and symbol you can type. Computers don't understand letters like 'A' or 'b'; they only understand numbers. ASCII translates our human-readable characters into a numerical format.
Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.