    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 depends upon the
     given [[base|radix]]:

     - For base 10, the accepted syntax 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. That is, an optional sign character, followed
       be a string of decimal digits, followed by an optional SI
       magnitude: `k`, `M`, `G`, `T`, or `P`.
     - For other bases, the accepted syntax is an optional sign
       character, followed by a string of digits of the given
       base.

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

         Integer: Base10 | BaseN
         Base10: Sign? Base10Digits Magnitude
         BaseN: Sign? BaseNDigits
         Sign: '+' | '-'
         Magnitude: 'k' | 'M' | 'G' | 'T' | 'P'
         Base10Digits: ('0'..'9')+
         BaseNDigits: ('0'..'9'|'a'..'z'|'A'..'Z')+"
    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;
    }