Skip to content

ASCII Table — Swift 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 Swift implementation — the same logic the interactive tool runs, in a shareable, citable form.

// ASCII Table — pure logic (Swift port): the 128-entry ASCII reference table with
// search and range filters.
//
// Language: Swift 5.9 — standard library only (no Foundation).
// Source: CosmoDev polyglot showcase port; canonical = src/lib/ascii-table.ts
//         + this tool's python.py / rust.rs.
// License: 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.

/// A single ASCII code point and its derived representations.
struct Entry: Equatable {
    /// Decimal code point, 0–127.
    let dec: Int
    /// Uppercase hex, e.g. "0x41".
    let hex: String
    /// Zero-padded 3-digit octal, e.g. "101".
    let oct: String
    /// Zero-padded 8-bit binary, e.g. "01000001".
    let binary: String
    /// Display glyph: the literal char for printables, a control-picture glyph otherwise.
    let char: String
    /// Human-readable name, e.g. "Line Feed (LF)", "Uppercase A", "Space".
    let name: String
    /// True for 32–126 (visible or space).
    let printable: Bool
    /// True for 0–31 and 127.
    let control: Bool
    /// C-style escape for control chars that have one (e.g. "\\n"); nil otherwise.
    let escape: String?
}

/// Namespace for the `ascii-table` tool's pure logic (a caseless enum is the
/// idiomatic un-instantiable namespace in Swift).
enum AsciiTable {

    /// Official ASCII control-character names for 0–31 and 127.
    ///
    /// Expressed as a `switch` over every control code point; the default arm
    /// is a defensive guard that documents the precondition (Rust's port uses
    /// `unreachable!()` for the same case).
    private static func controlName(_ code: Int) -> String {
        switch code {
        case 0: return "Null (NUL)"
        case 1: return "Start of Heading (SOH)"
        case 2: return "Start of Text (STX)"
        case 3: return "End of Text (ETX)"
        case 4: return "End of Transmission (EOT)"
        case 5: return "Enquiry (ENQ)"
        case 6: return "Acknowledge (ACK)"
        case 7: return "Bell (BEL)"
        case 8: return "Backspace (BS)"
        case 9: return "Horizontal Tab (HT)"
        case 10: return "Line Feed (LF)"
        case 11: return "Vertical Tab (VT)"
        case 12: return "Form Feed (FF)"
        case 13: return "Carriage Return (CR)"
        case 14: return "Shift Out (SO)"
        case 15: return "Shift In (SI)"
        case 16: return "Data Link Escape (DLE)"
        case 17: return "Device Control 1 (DC1)"
        case 18: return "Device Control 2 (DC2)"
        case 19: return "Device Control 3 (DC3)"
        case 20: return "Device Control 4 (DC4)"
        case 21: return "Negative Acknowledge (NAK)"
        case 22: return "Synchronous Idle (SYN)"
        case 23: return "End of Transmission Block (ETB)"
        case 24: return "Cancel (CAN)"
        case 25: return "End of Medium (EM)"
        case 26: return "Substitute (SUB)"
        case 27: return "Escape (ESC)"
        case 28: return "File Separator (FS)"
        case 29: return "Group Separator (GS)"
        case 30: return "Record Separator (RS)"
        case 31: return "Unit Separator (US)"
        case 127: return "Delete (DEL)"
        default:
            // Only called with control codes; defensive guard for misuse.
            return ""
        }
    }

    /// C-style escape for the control chars that own a standard/common one.
    /// Returns the literal 2-character source token (backslash + letter), or nil.
    private static func controlEscape(_ code: Int) -> String? {
        switch code {
        case 0: return "\\0"
        case 7: return "\\a"
        case 8: return "\\b"
        case 9: return "\\t"
        case 10: return "\\n"
        case 11: return "\\v"
        case 12: return "\\f"
        case 13: return "\\r"
        case 27: return "\\e"
        default: return nil
        }
    }

    /// Name for a printable punctuation / symbol glyph, or nil.
    /// Letters and digits are derived in `letterName(_:)`.
    private static func symbolName(_ code: Int) -> String? {
        switch code {
        case 32: return "Space"
        case 33: return "Exclamation mark"
        case 34: return "Quotation mark"
        case 35: return "Number sign"
        case 36: return "Dollar sign"
        case 37: return "Percent sign"
        case 38: return "Ampersand"
        case 39: return "Apostrophe"
        case 40: return "Left parenthesis"
        case 41: return "Right parenthesis"
        case 42: return "Asterisk"
        case 43: return "Plus sign"
        case 44: return "Comma"
        case 45: return "Hyphen / Minus"
        case 46: return "Full stop"
        case 47: return "Slash"
        case 58: return "Colon"
        case 59: return "Semicolon"
        case 60: return "Less-than sign"
        case 61: return "Equals sign"
        case 62: return "Greater-than sign"
        case 63: return "Question mark"
        case 64: return "At sign"
        case 91: return "Left bracket"
        case 92: return "Backslash"
        case 93: return "Right bracket"
        case 94: return "Circumflex / Caret"
        case 95: return "Underscore"
        case 96: return "Grave accent"
        case 123: return "Left brace"
        case 124: return "Vertical bar"
        case 125: return "Right brace"
        case 126: return "Tilde"
        default: return nil
        }
    }

    /// Derive a name for a printable letter or digit.
    private static func letterName(_ code: Int) -> String {
        let ch = Unicode.Scalar(code).map(String.init) ?? ""
        switch code {
        case 48...57: return "Digit \(code - 48)"      // '0'..'9'
        case 65...90: return "Uppercase \(ch)"         // 'A'..'Z'
        case 97...122: return "Lowercase \(ch)"        // 'a'..'z'
        default: return ch
        }
    }

    /// Render `value` in the given radix, zero-padded to `width` digits.
    /// (String(format:) would need Foundation; the stdlib has no printf.)
    private static func padded(_ value: Int, radix: Int, width: Int, uppercase: Bool = false) -> String {
        let digits = String(value, radix: radix, uppercase: uppercase)
        return String(repeating: "0", count: max(0, width - digits.count)) + digits
    }

    /// Trim ASCII/Unicode whitespace from both ends.
    /// (String.trimmingCharacters(in:) is a Foundation extension; Character.isWhitespace is stdlib.)
    private static func trimmed(_ s: String) -> String {
        var view = Substring(s)
        while let first = view.first, first.isWhitespace { view = view.dropFirst() }
        while let last = view.last, last.isWhitespace { view = view.dropLast() }
        return String(view)
    }

    /// Build a single entry from its code point (0–127).
    private static func makeEntry(_ code: Int) -> Entry {
        let control = code <= 31 || code == 127

        // Control-picture glyph: U+2400 for 0–31, U+2421 ("symbol for delete") for DEL.
        // Unicode.Scalar's init is failable — these code points are all valid
        // scalars, but we mirror the Rust port's defensive default instead of
        // force-unwrapping.
        let char = if control {
            Unicode.Scalar(code == 127 ? 0x2421 : 0x2400 + code).map(String.init) ?? ""
        } else {
            Unicode.Scalar(code).map(String.init) ?? ""
        }

        let name: String
        if control {
            name = controlName(code)
        } else if let symbol = symbolName(code) {
            name = symbol
        } else {
            name = letterName(code)
        }

        return Entry(
            dec: code,
            hex: "0x" + padded(code, radix: 16, width: 2, uppercase: true),
            oct: padded(code, radix: 8, width: 3),
            binary: padded(code, radix: 2, width: 8),
            char: char,
            name: name,
            printable: !control,
            control: control,
            escape: control ? controlEscape(code) : nil
        )
    }

    /// The full 128-entry ASCII table, indexed by code point.
    ///
    /// Stored as a static let: Swift initializes statics lazily, exactly once,
    /// thread-safely — the stdlib equivalent of Rust's `OnceLock`.
    static let entries: [Entry] = (0...127).map { makeEntry($0) }

    /// Look up a single entry by code point.
    ///
    /// Returns nil for out-of-range input; Swift optionals force callers to
    /// handle absence, like Rust's `Option` and the TypeScript variant's null.
    static func getEntry(_ code: Int) -> Entry? {
        guard (0...127).contains(code) else { return nil }
        return entries[code]
    }

    /// Filter the table.
    ///
    /// `query` is a case-insensitive substring matched against dec / hex / oct /
    /// binary / name / char / escape. `printableOnly` hides controls. `min` /
    /// `max` clamp the decimal range (defaults 0–127).
    static func filterTable(query: String = "", printableOnly: Bool = false,
                            min: Int = 0, max: Int = 127) -> [Entry] {
        let q = trimmed(query).lowercased()
        return entries.filter { e in
            if printableOnly && !e.printable { return false }
            if e.dec < min || e.dec > max { return false }
            if q.isEmpty { return true }
            let haystacks = [
                String(e.dec),
                e.hex.lowercased(),
                e.oct,
                e.binary,
                e.name.lowercased(),
                e.char.lowercased(),
                e.escape ?? "",
            ]
            return haystacks.contains { $0.contains(q) }
        }
    }
}

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 →