Sign in Join
Wiki copytemporary

Base converting

English · Français

The following unit will allow you to convert from one number base to another. Each base is chosen in the range 2..36.

Note, the unit does not know a negative sign.

Source

pascal
unit baseConvert;

// for exceptions
{$mode objfpc}

// P U B L I C ======================================================== //
interface
 
const
    /// list of symbols for integer representations
    digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';

function intToBaseStr(value: longword; const base: cardinal = 10): string;
function baseStrToInt(const value: string; const base: cardinal = 10): longword;

function baseToBase(
        const value: string;
        const interpretation: cardinal = 10;
        const base: cardinal = 10
    ): string;
 

// P R I V A T E ====================================================== //
implementation
 
uses
    // math unit for inRange and divMod routines
    math,
    // sysutils unit for ERangeError exception
    sysutils;

resourceString
    /// base not within range of available symbols
    errInvalidBase = '↯ b = %0:d! ⇒ b ∉ [%1:d, %2:d]';
    /// supplied character not within domain
    errInvalidSymbol = '↯ v(''%0:s'')↑; b = %1:d';
 
(**
    \brief expresses the value in the desired base
    
    \param value the value to convert
    \param base
    
    \return a string representing the number in given base
*)
function intToBaseStr(value: longword; const base: cardinal = 10): string;
var
    remainder: longword;
begin
    // validity of the base
    if not inRange(base, 2, length(digits)) then
    begin
        raise eRangeError.createFmt(errInvalidBase, [base, 2, length(digits)]);
    end;
    
    // decomposing the value: reverse Horner-scheme
    // The repeat-statement takes the value 0 into account.
    result := emptyStr;
    repeat
    begin
        divMod(value, base, value, remainder);
        // prepend value: intermediate results are read backwards
        result := digits[remainder + 1] + result;
    end
    until value = 0;
end;
 
(**
    \brief transforms the string of a number
           expressed in the parameter base
           into the equivalent integer
    
    \param value the representation of the integer
    \param base assume string is in given base
    
    If the string is empty, the result is 0.
    
    Caution:
    No verification of integer overflows.
    Reasonable values have to be used.
    
    \return the integer
*)
function baseStrToInt(const value: string; const base: cardinal = 10): longword;
var
    symbol: char;
    // beware, cardinal is _non-negative_
    digit: cardinal;
begin
    result := 0;
    // Horner-scheme
    for symbol in value do
    begin
        // determine ordinal value of current symbol
        digit := pos(symbol, digits);
        // If symbol wasn't found, pos returns 0.
        // Or possibly the symbol isn't known in the base.
        if not inRange(digit, 1, base) then
        begin
            raise eRangeError.createFmt(errInvalidSymbol, [symbol, base]);
        end;
        // e.g. the symbol '0' is the _first_ character in digits
        // thus the pos function returned 1 => here we subtract one
        dec(digit);
        result := result * base + digit;
    end;
end;
 
(**
    \brief direct conversion of number expressed in one base to another
    
    \param value the value to convert from
    \param interpretation the base to interpret the value as
    \param base the base to convert to
*)
function baseToBase(
        const value: string;
        const interpretation: cardinal = 10;
        const base: cardinal = 10
    ): string;
begin
    // the case interpretation = base
    // intentionally does not have special treatment for unit tests
    result := intToBaseStr(baseStrToInt(value, interpretation), base);
end;

// end of unit
end.

Remarks

For your information: For bases two, eight, ten, and sixteen, you can use binStr, OctStr, str and hexStr from the automatically included system unit.

Locales

en.po

bash
#: baseconvert:errinvalidbase
msgid "\342\206\257\302\240b\302\240= %0:d!\302\240\342\207\222 b\302\240\342\210\211\302\240[%1:d, %2:d]"
msgstr "Base %0:d is invalid. It must be between %1:d and %2:d."

#: baseconvert:errinvalidsymbol
msgid "\342\206\257\302\240v('%0:s')\342\206\221; b\302\240= %1:d"
msgstr "The symbol '%0:s' has an unacceptable value for base = %1:d."

de.po

bash
#: baseconvert:errinvalidbase
msgid "\342\206\257\302\240b\302\240= %0:d!\302\240\342\207\222 b\302\240\342\210\211\302\240[%1:d, %2:d]"
msgstr "Die Basis %0:d ist ungültig. Sie muß zwischen %1:d und %2:d sein."

#: baseconvert:errinvalidsymbol
msgid "\342\206\257\302\240v('%0:s')\342\206\221; b\302\240= %1:d"
msgstr "Der Zeichenwert von '%0:s' ist ungültig für Zahlen der Basis %1:d."

fr.po:

bash
#: baseconvert:errinvalidbase
msgid "\342\206\257\302\240b\302\240= %0:d!\302\240\342\207\222 b\302\240\342\210\211\302\240[%1:d, %2:d]"
msgstr "Base %0:d invalide, elle doit être comprise entre %1:d et %2:d."

#: baseconvert:errinvalidsymbol
msgid "\342\206\257\302\240v('%0:s')\342\206\221; b\302\240= %1:d"
msgstr "Mauvais chiffre '%0:s' dans la valeur, base = %1:d."

More ...

A more elaborate implementation (based upon the example code above) can be found in this FsiConv unit.
It has implementations for all integer types (signed and unsigned) as well as TryStrToXXX and StrToXXXDef functions.


From the Free Pascal wiki, page "Base converting", as it stood on 2022-05-26 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.

Revision 2, last changed by WikiArchive .

Talk about this page

Nobody has opened a bench for this page yet. Sign in to open one.