Difference between revisions of "Base converting"

From Free Pascal wiki
Jump to navigationJump to search
m (Replace deprecated enclose attributes)
 
(One intermediate revision by one other user not shown)
Line 2: Line 2:
 
{{Base_converting}}
 
{{Base_converting}}
  
The following [[Unit|<syntaxhighlight lang="pascal" enclose="none">unit</syntaxhighlight>]] will allow you to convert from one number base to another.
+
The following [[Unit|<syntaxhighlight lang="pascal" inline>unit</syntaxhighlight>]] will allow you to convert from one number base to another.
Each base is chosen in the range <syntaxhighlight lang="pascal" enclose="none">2..36</syntaxhighlight>.
+
Each base is chosen in the range <syntaxhighlight lang="pascal" inline>2..36</syntaxhighlight>.
  
 
Note, the unit does not know a negative sign.
 
Note, the unit does not know a negative sign.
  
== source ==
+
== Source ==
 
<syntaxhighlight lang="pascal" line>
 
<syntaxhighlight lang="pascal" line>
 
unit baseConvert;
 
unit baseConvert;
Line 139: Line 139:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== remarks ==
+
== Remarks ==
 +
 
 
For your information:
 
For your information:
 
For bases two, eight, ten, and sixteen, you can use <code>binStr</code>, <code>OctStr</code>, <code>str</code> and <code>hexStr</code> from the automatically included <code>system</code> unit.
 
For bases two, eight, ten, and sixteen, you can use <code>binStr</code>, <code>OctStr</code>, <code>str</code> and <code>hexStr</code> from the automatically included <code>system</code> unit.
  
== locales ==
+
== Locales ==
 +
 
 
<tt>en.po</tt>
 
<tt>en.po</tt>
 
<small><syntaxhighlight lang="bash">
 
<small><syntaxhighlight lang="bash">
Line 176: Line 178:
 
msgstr "Mauvais chiffre '%0:s' dans la valeur, base = %1:d."
 
msgstr "Mauvais chiffre '%0:s' dans la valeur, base = %1:d."
 
</syntaxhighlight></small>
 
</syntaxhighlight></small>
 +
 +
== More ... ==
 +
 +
A more elaborate implementation (based upon the example code above) can be found in [http://svn.code.sf.net/p/flyingsheep/code/trunk/MijnLib/fsiconv.pp this FsiConv unit].<br>
 +
It has implementations for all integer types (signed and unsigned) as well as TryStrToXXX and StrToXXXDef functions.

Latest revision as of 09:07, 26 May 2022

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

  1unit baseConvert;
  2
  3// for exceptions
  4{$mode objfpc}
  5
  6// P U B L I C ======================================================== //
  7interface
  8 
  9const
 10	/// list of symbols for integer representations
 11	digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
 12
 13function intToBaseStr(value: longword; const base: cardinal = 10): string;
 14function baseStrToInt(const value: string; const base: cardinal = 10): longword;
 15
 16function baseToBase(
 17		const value: string;
 18		const interpretation: cardinal = 10;
 19		const base: cardinal = 10
 20	): string;
 21 
 22
 23// P R I V A T E ====================================================== //
 24implementation
 25 
 26uses
 27	// math unit for inRange and divMod routines
 28	math,
 29	// sysutils unit for ERangeError exception
 30	sysutils;
 31
 32resourceString
 33	/// base not within range of available symbols
 34	errInvalidBase = '↯ b = %0:d! ⇒ b ∉ [%1:d, %2:d]';
 35	/// supplied character not within domain
 36	errInvalidSymbol = '↯ v(''%0:s'')↑; b = %1:d';
 37 
 38(**
 39	\brief expresses the value in the desired base
 40	
 41	\param value the value to convert
 42	\param base
 43	
 44	\return a string representing the number in given base
 45*)
 46function intToBaseStr(value: longword; const base: cardinal = 10): string;
 47var
 48	remainder: longword;
 49begin
 50	// validity of the base
 51	if not inRange(base, 2, length(digits)) then
 52	begin
 53		raise eRangeError.createFmt(errInvalidBase, [base, 2, length(digits)]);
 54	end;
 55	
 56	// decomposing the value: reverse Horner-scheme
 57	// The repeat-statement takes the value 0 into account.
 58	result := emptyStr;
 59	repeat
 60	begin
 61		divMod(value, base, value, remainder);
 62		// prepend value: intermediate results are read backwards
 63		result := digits[remainder + 1] + result;
 64	end
 65	until value = 0;
 66end;
 67 
 68(**
 69	\brief transforms the string of a number
 70	       expressed in the parameter base
 71	       into the equivalent integer
 72	
 73	\param value the representation of the integer
 74	\param base assume string is in given base
 75	
 76	If the string is empty, the result is 0.
 77	
 78	Caution:
 79	No verification of integer overflows.
 80	Reasonable values have to be used.
 81	
 82	\return the integer
 83*)
 84function baseStrToInt(const value: string; const base: cardinal = 10): longword;
 85var
 86	symbol: char;
 87	// beware, cardinal is _non-negative_
 88	digit: cardinal;
 89begin
 90	result := 0;
 91	// Horner-scheme
 92	for symbol in value do
 93	begin
 94		// determine ordinal value of current symbol
 95		digit := pos(symbol, digits);
 96		// If symbol wasn't found, pos returns 0.
 97		// Or possibly the symbol isn't known in the base.
 98		if not inRange(digit, 1, base) then
 99		begin
100			raise eRangeError.createFmt(errInvalidSymbol, [symbol, base]);
101		end;
102		// e.g. the symbol '0' is the _first_ character in digits
103		// thus the pos function returned 1 => here we subtract one
104		dec(digit);
105		result := result * base + digit;
106	end;
107end;
108 
109(**
110	\brief direct conversion of number expressed in one base to another
111	
112	\param value the value to convert from
113	\param interpretation the base to interpret the value as
114	\param base the base to convert to
115*)
116function baseToBase(
117		const value: string;
118		const interpretation: cardinal = 10;
119		const base: cardinal = 10
120	): string;
121begin
122	// the case interpretation = base
123	// intentionally does not have special treatment for unit tests
124	result := intToBaseStr(baseStrToInt(value, interpretation), base);
125end;
126
127// end of unit
128end.

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.