ASCII Table — Python source
A searchable, filterable reference for all 128 ASCII code points. See the decimal, hex, octal, and binary form of every character, narrow to printable characters only, clamp the code-point range, and click any row to copy. Runs 100% client-side.
This is the Python implementation — the same logic the interactive tool runs, in a shareable, citable form.
"""ASCII Table — pure logic (Python port).
CosmoDev polyglot showcase port of the `ascii-table` tool, ported from
``src/lib/ascii-table.ts``. Every output is a pure function of the code point
0–127; no I/O, no third-party packages — the Python standard library only.
Display source — part of CosmoDev's polyglot tool pages.
Each of the 128 ASCII code points is described by its decimal / hex / octal /
binary forms, a display glyph, a human name, whether it is printable, whether
it is a control character, and (for control chars that have one) a C-style
escape sequence.
"""
from __future__ import annotations
from dataclasses import dataclass
from functools import lru_cache
from typing import Optional
@dataclass(frozen=True)
class Entry:
"""A single ASCII code point and its derived representations."""
dec: int
hex: str
oct: str
binary: str
char: str
name: str
printable: bool
control: bool
escape: Optional[str] = None
# Official ASCII control-character names (0–31 and 127).
_CONTROL_NAMES = {
0: "Null (NUL)",
1: "Start of Heading (SOH)",
2: "Start of Text (STX)",
3: "End of Text (ETX)",
4: "End of Transmission (EOT)",
5: "Enquiry (ENQ)",
6: "Acknowledge (ACK)",
7: "Bell (BEL)",
8: "Backspace (BS)",
9: "Horizontal Tab (HT)",
10: "Line Feed (LF)",
11: "Vertical Tab (VT)",
12: "Form Feed (FF)",
13: "Carriage Return (CR)",
14: "Shift Out (SO)",
15: "Shift In (SI)",
16: "Data Link Escape (DLE)",
17: "Device Control 1 (DC1)",
18: "Device Control 2 (DC2)",
19: "Device Control 3 (DC3)",
20: "Device Control 4 (DC4)",
21: "Negative Acknowledge (NAK)",
22: "Synchronous Idle (SYN)",
23: "End of Transmission Block (ETB)",
24: "Cancel (CAN)",
25: "End of Medium (EM)",
26: "Substitute (SUB)",
27: "Escape (ESC)",
28: "File Separator (FS)",
29: "Group Separator (GS)",
30: "Record Separator (RS)",
31: "Unit Separator (US)",
127: "Delete (DEL)",
}
# C-style escape sequences for the control chars that have a standard/common
# one. Each value is the literal 2-character source token (backslash + letter).
_ESCAPES = {
0: "\\0",
7: "\\a",
8: "\\b",
9: "\\t",
10: "\\n",
11: "\\v",
12: "\\f",
13: "\\r",
27: "\\e",
}
# Names for printable punctuation & symbols; letter and digit names are derived.
_SYMBOL_NAMES = {
32: "Space",
33: "Exclamation mark",
34: "Quotation mark",
35: "Number sign",
36: "Dollar sign",
37: "Percent sign",
38: "Ampersand",
39: "Apostrophe",
40: "Left parenthesis",
41: "Right parenthesis",
42: "Asterisk",
43: "Plus sign",
44: "Comma",
45: "Hyphen / Minus",
46: "Full stop",
47: "Slash",
58: "Colon",
59: "Semicolon",
60: "Less-than sign",
61: "Equals sign",
62: "Greater-than sign",
63: "Question mark",
64: "At sign",
91: "Left bracket",
92: "Backslash",
93: "Right bracket",
94: "Circumflex / Caret",
95: "Underscore",
96: "Grave accent",
123: "Left brace",
124: "Vertical bar",
125: "Right brace",
126: "Tilde",
}
def _letter_name(code: int) -> str:
"""Derive a name for a printable letter or digit."""
if 48 <= code <= 57: # '0'..'9'
return f"Digit {code - 48}"
if 65 <= code <= 90: # 'A'..'Z'
return f"Uppercase {chr(code)}"
if 97 <= code <= 122: # 'a'..'z'
return f"Lowercase {chr(code)}"
return chr(code)
def _make_entry(code: int) -> Entry:
"""Build a single entry from its code point (0–127)."""
control = code <= 31 or code == 127
# Control-picture glyph: U+2400 for 0–31, U+2421 ("symbol for delete") for DEL.
if control:
char = chr(0x2421 if code == 127 else 0x2400 + code)
else:
char = chr(code)
if control:
name = _CONTROL_NAMES[code]
else:
name = _SYMBOL_NAMES.get(code) or _letter_name(code)
escape = _ESCAPES.get(code) if control else None
return Entry(
dec=code,
hex=f"0x{code:02X}",
oct=f"{code:03o}",
binary=f"{code:08b}",
char=char,
name=name,
printable=not control,
control=control,
escape=escape,
)
@lru_cache(maxsize=1)
def entries() -> tuple[Entry, ...]:
"""The full 128-entry ASCII table, indexed by code point.
Built once and cached for the process lifetime (the table is immutable, so
a shared tuple is safe for all callers).
"""
return tuple(_make_entry(i) for i in range(128))
def get_entry(code: int) -> Optional[Entry]:
"""Look up a single entry by code point.
Returns ``None`` for out-of-range or non-integer input. Booleans are
rejected explicitly: in Python ``bool`` subclasses ``int``, so ``True`` and
``False`` would otherwise leak through as ``1`` and ``0``. TypeScript's
``Number.isInteger`` treats booleans as non-numbers, and we mirror that.
"""
if isinstance(code, bool) or not isinstance(code, int):
return None
if code < 0 or code > 127:
return None
return entries()[code]
def filter_table(
query: str = "",
printable_only: bool = False,
min: int = 0, # noqa: A002 - mirrors the tool's public parameter names
max: int = 127, # noqa: A002 - mirrors the tool's public parameter names
) -> list[Entry]:
"""Filter the table.
``query`` is a case-insensitive substring matched against dec / hex / oct /
binary / name / char / escape. ``printable_only`` hides controls.
``min`` / ``max`` clamp the decimal range (defaults 0–127).
"""
q = (query or "").strip().lower()
out: list[Entry] = []
for e in entries():
if printable_only and not e.printable:
continue
if e.dec < min or e.dec > max:
continue
if not q:
out.append(e)
continue
haystack = (
str(e.dec),
e.hex.lower(),
e.oct,
e.binary,
e.name.lower(),
e.char.lower(),
e.escape or "",
)
if any(q in h for h in haystack):
out.append(e)
return out
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →