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.

Reference·61 commands·Last updated 2026-07-21
asciiEncodingCharacter Sets

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)
NUL, the null character that terminates C strings
3 (0x03)
ETX, end of text; Ctrl+C sends an interrupt signal
4 (0x04)
EOT, end of transmission; Ctrl+D signals end of input (EOF)
7 (0x07)
BEL, bell; rings the terminal beep
8 (0x08)
BS, backspace
9 (0x09)
HT, horizontal tab
10 (0x0A)
LF, line feed
11 (0x0B)
VT, vertical tab
12 (0x0C)
FF, form feed
13 (0x0D)
CR, carriage return
26 (0x1A)
SUB, substitute; Ctrl+Z suspends or marks EOF
27 (0x1B)
ESC, escape; starts terminal ANSI sequences
127 (0x7F)
DEL Delete

Printable Characters (32-126) 8

32 (0x20)
Space, the lowest printable character
33-47 (0x21-0x2F)
Punctuation and symbols
48-57 (0x30-0x39)
Digits 0-9
58-64 (0x3A-0x40)
Punctuation and symbols
65-90 (0x41-0x5A)
Uppercase letters A-Z
91-96 (0x5B-0x60)
Punctuation and symbols
97-122 (0x61-0x7A)
Lowercase letters a-z
123-126 (0x7B-0x7E)
Punctuation and symbols

Common Control Characters 8

LF (10)
Line terminator on Unix/Linux/macOS
CR (13)
Line terminator on classic Mac OS (9 and earlier)
CRLF (13+10)
Line terminator on Windows/DOS
HT (9)
Tab character, used for indentation and alignment
ESC (27)
Starts terminal ANSI escape sequences (colour, cursor control)
DEL (127)
Deletes the character before the cursor
NUL (0)
Terminator of C language strings
ETX (3)
Ctrl+C sends an interrupt signal to the process

Extended ASCII (128-255) 9

128-159 (0x80-0x9F)
Extended control characters (the C1 control set)
160 (0xA0)
NBSP, non-breaking space
169 (0xA9)
© copyright symbol
174 (0xAE)
® registered trademark symbol
176 (0xB0)
° degree symbol
177 (0xB1)
± plus-minus sign
181 (0xB5)
µ micro sign
215 (0xD7)
× multiplication sign
247 (0xF7)
÷ division sign

Encoding Conversion Reference 7

A (65)
Hex 0x41 / octal 0101 / binary 01000001
a (97)
Hex 0x61 / octal 0141 / binary 01100001
0 (48)
Hex 0x30 / octal 0060 / binary 00110000
Space (32)
Hex 0x20 / octal 0040 / binary 00100000
LF (10)
Hex 0x0A / octal 0012 / binary 00001010
CR (13)
Hex 0x0D / octal 0015 / binary 00001101
~ (126)
Hex 0x7E / octal 0176 / binary 01111110

Language Conversion 8

JS decimal to character
String.fromCharCode(65) -> "A"
JS character to decimal
"A".charCodeAt(0) -> 65
JS decimal to hex
(65).toString(16) -> "41"
JS hex to decimal
parseInt("41", 16) -> 65
Python decimal to character
chr(65) -> "A"
Python character to decimal
ord("A") -> 65
Python decimal to hex
hex(65) -> "0x41"
C escape sequences
\n=10, \t=9, \r=13, \0=0, \\=92

Quick Conventions 8

Case difference
Upper and lowercase forms of a letter differ by 32 (0x20)
Upper to lower
Add 32, i.e. OR with 0x20 ("A" | 0x20 -> "a")
Lower to upper
Subtract 32, i.e. AND with 0xDF ("a" & 0xDF -> "A")
Digit char to value
Subtract 48 from the char code ('0' -> 0)
Printable range
32-126, 95 printable characters in total
Contiguous letter ranges
0-9: 48-57, A-Z: 65-90, a-z: 97-122
Highest ASCII value
127 (0x7F) DEL; standard ASCII has 128 codes
Special role of space
32 is the lowest printable character and the usual delimiter

Parameter matrix

ParameterEffectExample
control codes 0-31 / 127look up the code point and terminal key binding of an invisible character10 (0x0A) :: LF line feed
printable range 32-126decide whether a code point is human-readable text, the first filter for binary data32-126 is 95 printable characters in total
line endings LF / CR / CRLFtell Unix, classic Mac and Windows endings apart when a file has mixed line endingsCRLF (13+10) :: Windows/DOS line ending
JS / Python convertersconvert between a character and its decimal code point in either directionString.fromCharCode(65) -> "A"
32-step case differenceflip case or turn a digit character into a number with arithmetic onlyupper 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

  1. 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.

  2. 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.

  3. 3Find which control characters slipped into a file

    grep -P -n "[\x00-\x08\x0b\x0c\x0e-\x1f]" README.md

    Any 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 -c

The 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 &nbsp;, 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