    Integer minRadix = 2;
    Integer maxRadix = 36;

    "The [[Integer]] value of the given
     [[string representation|string]] of an integer value in the
     base given by [[radix]], or `null` if the string does not
     represent an integer in that base, or if the mathematical
     integer it represents is too large in magnitude to be
     represented by an instance of the class `Integer`.

     The syntax accepted by this function is the same as the
     syntax for an `Integer` literal in the Ceylon language
     except that it may optionally begin with a sign character
     (`+` or `-`) and may not contain grouping underscore
     characters.

     The given `radix` specifies the base of the string
     representation. The list of available digits starts from
     `0` to `9`, followed by `a` to `z`. When parsing in a
     specific base, the first `radix` digits from the available
     digits list is used. This function is not case sensitive;
     `a` and `A` both correspond to the digit `a` whose decimal
     value is `10`."
    throws (`class AssertionError`,
            "if [[radix]] is not between [[minRadix]] and
             [[maxRadix]]")
    see (`function formatInteger`,
         `function parseFloat`)
    tagged("Numbers", "Basic types")
    shared Integer? parseInteger(
                "The string representation to parse."
                String string,
                "The base, between [[minRadix]] and [[maxRadix]]
                 inclusive."
                Integer radix = 10) {

        assert (minRadix <= radix <= maxRadix);

        Integer start;
        Integer max = runtime.minIntegerValue / radix;

        // Parse the sign
        Boolean negative;
        if (exists char = string.first) {
            if (char == '-') {
                negative = true;
                start = 1;
            }
            else if (char == '+') {
                negative = false;
                start = 1;
            }
            else {
                negative = false;
                start = 0;
            }
        }
        else {
            return null;
        }

        Integer limit = negative
                then runtime.minIntegerValue
                else -runtime.maxIntegerValue;

        Integer length = string.size;
        variable Integer result = 0;
        variable Integer digitIndex = 0;
        variable Integer index = start;
        while (index < length) {
            assert (exists ch = string.getFromFirst(index));

            if (index + 1 == length &&
                    radix == 10 &&
                    ch in "kMGTP") {
                // The SI-style magnitude
                if (exists exp = parseIntegerExponent(ch)) {
                    Integer magnitude = 10^exp;
                    if ((limit / magnitude) < result) {
                        result *= magnitude;
                        break;
                    }
                    else {
                        // overflow
                        return null;
                    }
                }
                else {
                    return null;
                }
            }
            else if (exists digit = parseDigit(ch, radix)) {
                // A regular digit
                if (result < max) {
                    // overflow
                    return null;
                }
                result *= radix;
                if (result < limit + digit) {
                    // overflow
                    return null;
                }
                // += would be much more obvious, but it doesn't work for minIntegerValue
                result -= digit;
            }
            else {
                // Invalid character
                return null;
            }

            index++;
            digitIndex++;
        }

        if (digitIndex == 0) {
            return null;
        }
        else {
            return negative then result else -result;
        }
    }

    Integer? parseIntegerExponent(Character char) {
        switch (char)
        case ('P') {
            return 15;
        }
        case ('T') {
            return 12;
        }
        case ('G') {
            return 9;
        }
        case ('M') {
            return 6;
        }
        case ('k') {
            return 3;
        }
        else {
            return null;
        }
    }

    Integer aIntLower = 'a'.integer;
    Integer aIntUpper = 'A'.integer;
    Integer zeroInt = '0'.integer;

    Integer? parseDigit(Character digit, Integer radix) {
        Integer figure;
        Integer digitInt = digit.integer;
        if (0<=digitInt-zeroInt<10) {
            figure=digitInt-zeroInt;
        }
        else if (0<=digitInt-aIntLower<26) {
            figure=digitInt-aIntLower+10;
        }
        else if (0<=digitInt-aIntUpper<26) {
            figure=digitInt-aIntUpper+10;
        }
        else {
            return null;
        }
        return figure<radix then figure;
    }