Skip to content

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

// ASCII Table — pure logic (Java port): the 128-entry ASCII reference table with
// search and range filters.
//
// Language: Java 17 — standard library only (java.lang / java.util).
// 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.
//
// The types are package-private: the polyglot layout fixes this file's name
// (java.java), so it cannot match the type name as javac requires for public
// top-level types.

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Optional;

/**
 * A single ASCII code point and its derived representations.
 *
 * @param dec       decimal code point, 0–127
 * @param hex       uppercase hex, e.g. "0x41"
 * @param oct       zero-padded 3-digit octal, e.g. "101"
 * @param binary    zero-padded 8-bit binary, e.g. "01000001"
 * @param glyph     display glyph: the literal char for printables, a
 *                  control-picture glyph otherwise (named {@code char} in the
 *                  canonical sources; that is a keyword here)
 * @param name      human-readable name, e.g. "Line Feed (LF)", "Uppercase A"
 * @param printable true for 32–126 (visible or space)
 * @param control   true for 0–31 and 127
 * @param escape    C-style escape for control chars that have one (e.g. "\n");
 *                  null otherwise
 */
record Entry(int dec, String hex, String oct, String binary, String glyph, String name,
             boolean printable, boolean control, String escape) {
}

/** The {@code ascii-table} tool's pure logic. */
final class AsciiTable {

    private AsciiTable() {
    }

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

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

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

    /** Derive a name for a printable letter or digit. */
    private static String letterName(int code) {
        if (code >= 48 && code <= 57)         // '0'..'9'
            return "Digit " + (code - 48);
        if (code >= 65 && code <= 90)         // 'A'..'Z'
            return "Uppercase " + (char) code;
        if (code >= 97 && code <= 122)        // 'a'..'z'
            return "Lowercase " + (char) code;
        return String.valueOf((char) code);
    }

    /** Zero-pad a radix string to {@code width} digits (Java has no "%b"/width fill for binary). */
    private static String pad(String digits, int width) {
        return "0".repeat(width - digits.length()) + digits;
    }

    /** Build a single entry from its code point (0–127). */
    private static Entry makeEntry(int code) {
        boolean control = code <= 31 || code == 127;

        // Control-picture glyph: U+2400 for 0–31, U+2421 ("symbol for delete") for DEL.
        String glyph = control
                ? new String(Character.toChars(code == 127 ? 0x2421 : 0x2400 + code))
                : String.valueOf((char) code);

        String symbol = symbolName(code);
        String name = control ? controlName(code)
                : symbol != null ? symbol : letterName(code);

        return new Entry(
                code,
                String.format("0x%02X", code),
                String.format("%03o", code),
                pad(Integer.toBinaryString(code), 8),
                glyph,
                name,
                !control,
                control,
                control ? controlEscape(code) : null);
    }

    // The 128-entry table is built once in the class initializer. The JLS
    // (§12.4.2) guarantees class initialization runs exactly once,
    // thread-safely — the JVM equivalent of Rust's OnceLock.
    private static final List<Entry> ENTRIES = buildEntries();

    private static List<Entry> buildEntries() {
        List<Entry> table = new ArrayList<>(128);
        for (int i = 0; i < 128; i++)
            table.add(makeEntry(i));
        return List.copyOf(table);
    }

    /** The full 128-entry ASCII table, indexed by code point (immutable). */
    public static List<Entry> entries() {
        return ENTRIES;
    }

    /**
     * Look up a single entry by code point.
     *
     * <p>Returns {@link Optional#empty()} for out-of-range input — the idiomatic
     * Java equivalent of the TypeScript variant's null and Rust's Option,
     * forcing callers to handle absence.
     */
    public static Optional<Entry> getEntry(int code) {
        if (code < 0 || code > 127)
            return Optional.empty();
        return Optional.of(ENTRIES.get(code));
    }

    /** {@link #filterTable} with all defaults. */
    public static List<Entry> filterTable() {
        return filterTable("", false, 0, 127);
    }

    /**
     * Filter the table.
     *
     * <p>{@code query} is a case-insensitive substring matched against dec /
     * hex / oct / binary / name / char / escape. {@code printableOnly} hides
     * controls. {@code min} / {@code max} clamp the decimal range (defaults
     * 0–127).
     */
    public static List<Entry> filterTable(String query, boolean printableOnly, int min, int max) {
        String q = (query == null ? "" : query).strip().toLowerCase(Locale.ROOT);
        List<Entry> result = new ArrayList<>();
        for (Entry e : ENTRIES) {
            if (printableOnly && !e.printable())
                continue;
            if (e.dec() < min || e.dec() > max)
                continue;
            if (!q.isEmpty()) {
                boolean hit = Integer.toString(e.dec()).contains(q)
                        || e.hex().toLowerCase(Locale.ROOT).contains(q)
                        || e.oct().contains(q)
                        || e.binary().contains(q)
                        || e.name().toLowerCase(Locale.ROOT).contains(q)
                        || e.glyph().toLowerCase(Locale.ROOT).contains(q)
                        || (e.escape() != null && e.escape().contains(q));
                if (!hit)
                    continue;
            }
            result.add(e);
        }
        return result;
    }
}

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 →