Base converting
From Free Pascal wiki
Jump to navigationJump to search
│
English (en) │
français (fr) │
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
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
#: 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
#: 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:
#: 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.