ASCII Code Cheatsheet - ASCII Character Encoding Reference
Protocol and encoding bugs usually boil down to "which byte is which char". This table lists ASCII 0–127 split into control and printable characters, each with decimal, hex, octal and the HTML entity, plus Latin-1 extension notes and per-language conversion tips. Use it to decode raw bytes, format terminal-control escapes, and understand what \n \r \t \0 really are. After reading you can translate between representations by hand.
Typical Use Case
For developers who work directly with bytes: debugging mojibake, locating invisible control characters, decoding hex fragments found in files, and converting between characters and numbers in JS or Python. This sheet keeps three groups together — control codes (0-31, 127), the printable range (32-126), and extended characters (128-255) — plus the arithmetic rule behind case conversion (a 32-step difference). The most common uses are: a JSON parse failure caused by an invisible character in production logs, and confirming whether a file actually uses LF or CRLF line endings.
Control Characters (0-31, 127) 13
0 (0x00)3 (0x03)4 (0x04)7 (0x07)8 (0x08)9 (0x09)10 (0x0A)11 (0x0B)12 (0x0C)13 (0x0D)26 (0x1A)27 (0x1B)127 (0x7F)Printable Characters (32-126) 8
32 (0x20)33-47 (0x21-0x2F)48-57 (0x30-0x39)58-64 (0x3A-0x40)65-90 (0x41-0x5A)91-96 (0x5B-0x60)97-122 (0x61-0x7A)123-126 (0x7B-0x7E)Common Control Characters 8
LF (10)CR (13)CRLF (13+10)HT (9)ESC (27)DEL (127)NUL (0)ETX (3)Extended ASCII (128-255) 9
128-159 (0x80-0x9F)160 (0xA0)169 (0xA9)174 (0xAE)176 (0xB0)177 (0xB1)181 (0xB5)215 (0xD7)247 (0xF7)Encoding Conversion Reference 7
A (65)a (97)0 (48)Space (32)LF (10)CR (13)~ (126)Language Conversion 8
JS decimal to characterJS character to decimalJS decimal to hexJS hex to decimalPython decimal to characterPython character to decimalPython decimal to hexC escape sequencesQuick Conventions 8
Case differenceUpper to lowerLower to upperDigit char to valuePrintable rangeContiguous letter rangesHighest ASCII valueSpecial role of spaceParameter matrix
| Parameter | Effect | Example |
|---|---|---|
control codes 0-31 / 127 | look up the code point and terminal key binding of an invisible character | 10 (0x0A) :: LF line feed |
printable range 32-126 | decide whether a code point is human-readable text, the first filter for binary data | 32-126 is 95 printable characters in total |
line endings LF / CR / CRLF | tell Unix, classic Mac and Windows endings apart when a file has mixed line endings | CRLF (13+10) :: Windows/DOS line ending |
JS / Python converters | convert between a character and its decimal code point in either direction | String.fromCharCode(65) -> "A" |
32-step case difference | flip case or turn a digit character into a number with arithmetic only | upper to lower: add 32, or OR with 0x20 ("A" | 0x20 -> "a") |
Common pitfalls
SymptomWriting ESC (27) into a document or log makes the terminal swallow the characters after it.
CauseESC starts an ANSI escape sequence, so the terminal reads it plus the following bytes as a command.
FixRender the key as its visible form (Ctrl+[ prints ^[) or write it as the label ESC (27) instead of the byte.
SymptomA file looks fine in a Windows editor but collapses into a single line in a Linux script.
CauseWindows writes CRLF (13+10) while Unix only treats LF (10) as the line break, leaving a stray CR.
FixNormalize on read by splitting on CRLF, or strip trailing CRs with sed -i "s/\r$//".
SymptomPressing Backspace deletes only half the character and leaves an invisible one behind.
CauseTerminals may send 8 (BS) or 127 (DEL) for Backspace, and the two mean different things.
FixTreat 127 (DEL) as delete-the-character-after-cursor and 8 (BS) as a plain backspace step.
SymptomA code copied out of a hex dump decodes into a negative number or garbage.
CauseStandard ASCII stops at 127 (0x7F); 128-159 (0x80-0x9F) is the extended control set, not printable text.
FixJudge printability only on 32-126, and handle anything above 128 as an extended char or UTF-8 multibyte sequence.
Troubleshooting
1Look up a character code point and confirm whether it is printable
node -e "const c=process.argv[1];console.log(c, c.charCodeAt(0), c.charCodeAt(0)>=32&&c.charCodeAt(0)<=126)" "A"Prints the code point and whether it lands in 32-126; false means it is a control character.
2Turn a decimal code point into a character to see what it actually is
node -e "console.log(JSON.stringify(String.fromCharCode(65)))"JSON.stringify wraps the result so a control character cannot scramble the terminal.
3Find which control characters slipped into a file
grep -P -n "[\x00-\x08\x0b\x0c\x0e-\x1f]" README.mdAny output means control characters are present, and the line number points straight at them.
Command Examples
Converting characters, code points and hex in Node
node -e "
const ch = 'A';
console.log(ch.charCodeAt(0), (65).toString(16), parseInt('41', 16), String.fromCharCode(65));
console.log('A'.charCodeAt(0) | 0x20, 'a'.charCodeAt(0) & 0xDF);
console.log('7'.charCodeAt(0) - 48);
"Line two is the bitwise form of the 32-step rule: OR 0x20 lowercases, AND 0xDF uppercases. Line three turns a digit character into its numeric value by subtracting 48.
Output
65 41 65 A 97 65 7
Python ord, chr, hex and oct
python -c "
s = 'A'
print(ord(s), hex(ord(s)), chr(65), oct(65))
print(ord('A') - ord('a'))
"ord yields the code point and chr builds the character back; hex and oct line up with the hexadecimal and octal columns of the table. The last line confirms the 32-step case difference.
Output
65 0x41 A 0o101 -32
Revealing tabs and both line endings with od -c
printf 'a\tb\n' | od -c
printf 'a\r\nb\n' | od -cThe first dump is LF (code point 10) plus HT (9). The second shows the Windows CRLF pair as two bytes, 13 and 10, and the offset grows from 4 to 5.
Output
0000000 a \t b \n 0000004 0000000 a \r \n b \n 0000005
Scanning a line for every control code point
node -e "
const line = 'ok\tvalue\r\n';
const bad = [...line].map((c, i) => [i, c.codePointAt(0)]).filter(([, c]) => c < 32 && c !== 0);
console.log(JSON.stringify(bad.map(([i, c]) => i + ':' + c)));
"Index 2 is the tab (9); indices 8 and 9 are the two bytes of CRLF (13 and 10). This sweep is the quickest way to see which control characters a file actually contains.
Output
["2:9","8:13","9:10"]
Common Pitfalls
- Never type ESC (27) straight into docs, commit messages or logs: the terminal swallows it and everything after it, so pasted content silently loses a chunk.
- Normalize line endings before moving text between platforms. Mixing LF (10) with CRLF (13+10) inside one file collapses it into a single line under Linux scripts.
- Beware DEL (127) when deleting with Backspace: some programs remove a single byte and leave an invisible NUL (0) or other control character at the end.
- Do not keep reading a negative code point or one above 127 as ASCII. It is extended ASCII or a UTF-8 multi-byte sequence; settle the encoding first.
- NBSP (160) looks identical to a space (32) yet breaks string equality, URL encoding and unique indexes. Normalize before deduplicating.
Tips
- ASCII covers only 0-127; beyond that use Unicode (e.g. UTF-8).
- Newline is LF (10) on Linux/macOS, CRLF (13+10) on Windows — watch out when transferring text cross-platform.
- Control characters are non-printable but used in protocol control (ESC sequences, terminal colors).
- Upper/lower case differ by 32 (0x20): uppercase to lowercase OR 0x20; lowercase to uppercase AND 0xDF.
- 128-255 is extended ASCII (Latin-1/ISO-8859-1), whose meaning varies by encoding (GBK/Shift-JIS).
FAQ
Why does ASCII stop at 127 yet 128-255 keeps coming up?
The 0-127 range is the minimal set frozen into ANSI X3.4, inherited from telegraph code; seven bits consume it exactly, hence "7-bit ASCII". 128-255 is not ASCII at all: IBM PC later filled the upper half of the byte with extended graphics, and that region became known as Latin-1 or ISO-8859-1. The same number means different things per encoding — 160 is a non-breaking space in Latin-1 but a control symbol in some terminal tables — so you must establish the encoding before trusting a byte value.
Why do ranges 33-47 and 58-64 contain nothing but punctuation?
It is an artifact of a 7-bit encoding. 65-90 went to capital letters and 97-122 to their lowercase twins; each script had to occupy 26 consecutive slots because the old uppercase-only systems relied on subtracting 32 to recover lowercase. Everything still unclaimed went to digits, punctuation and controls. That is why 33-47, 58-64, 91-96 and 123-126 are all symbols: they are the leftover printable space, 32 characters in total, not a design preference.
When does the 32-step case conversion rule break down?
It only holds inside the ASCII letter ranges. OR-ing 0x20 onto a digit or punctuation returns the very same character, so the bit trick silently does nothing there. It is valid only when the code point sits in 65-90 or 97-122. Once you cross 127 — extended ASCII, or any multi-byte UTF-8 sequence — the arithmetic yields a meaningless value. Full-width characters and non-Latin scripts need the language library own case functions instead.
Why is NBSP (160) harder to spot than a plain space (32)?
Both render as a blank with no visible glyph; the only differences are whether a line break may occur there and the byte value itself. It slips in from web copy-paste, Word exports or the HTML entity , and the symptom is a string comparison that fails, a URL carrying %C2%A0, or a unique index collision — all invisible on screen. Detecting it means comparing code points: check whether the value is 32 or 160 rather than reading the rendered text.
Why does looking up a code point sometimes yield garbled text?
A code point only means something inside its own encoding. fromCharCode(65) reliably gives A because 65 is A everywhere; 0xE4 in UTF-8 is not a standalone character but a continuation-byte marker, so reading it as a single byte produces noise. Conversely a CJK character occupies three UTF-8 bytes and must be decoded as a whole sequence, so a per-byte table lookup always fails. Determine the encoding first, then decode the full byte run under that encoding rules.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us