Eddie Shipman
asked on
Delphi->PHP Conversion .
I have a need for some Integer to base36 conversions.
I have the code in Delphi but need a PHP version now.
Here is the Delphi code:
const XX = '0123456789ABCDEFGHIJKLMNO PQRSTUVWXY Z' ;
Function Base36ToInt (const S: string): Int64;
var i: integer;
begin
Result := 0;
For i := 1 to length(S) do
Result := Result * 36 + Pred(Pos(UpCase(S[i]), XX)) ;
end;
Function IntegerToBase36 (I: Int64): string;
begin
Result := '';
Repeat
Result := XX[Succ(I mod 36)] + Result ;
I := I div 36;
Until I=0;
end;
Using base_convert DOES NOT work the same and returns a
different result. I need the code above converted directly.
Here is sample data:
Integer passed: 5555444433331111
String Result: 177XYGYLBFLZ4
Using this PHP code:
function base36toint($s){
$x = base_convert($s, 36, 10);
return $x;
}
function inttobase36($s) {
$x = base_convert($s, 10, 36);
return $x;
}
results in this: 1ip8nxua3s7
Another developer using the exact same PHP code
gets a different result than I, why?
I have the code in Delphi but need a PHP version now.
Here is the Delphi code:
const XX = '0123456789ABCDEFGHIJKLMNO
Function Base36ToInt (const S: string): Int64;
var i: integer;
begin
Result := 0;
For i := 1 to length(S) do
Result := Result * 36 + Pred(Pos(UpCase(S[i]), XX)) ;
end;
Function IntegerToBase36 (I: Int64): string;
begin
Result := '';
Repeat
Result := XX[Succ(I mod 36)] + Result ;
I := I div 36;
Until I=0;
end;
Using base_convert DOES NOT work the same and returns a
different result. I need the code above converted directly.
Here is sample data:
Integer passed: 5555444433331111
String Result: 177XYGYLBFLZ4
Using this PHP code:
function base36toint($s){
$x = base_convert($s, 36, 10);
return $x;
}
function inttobase36($s) {
$x = base_convert($s, 10, 36);
return $x;
}
results in this: 1ip8nxua3s7
Another developer using the exact same PHP code
gets a different result than I, why?
ooops, now I see they are not the same :(
Must be a rounding error in base_convert, how ugly!
Must be a rounding error in base_convert, how ugly!
ok, a little more testing:
on linux php 4.3.8 there is no error
on windows php 5.0 there is a rounding error, very ugly!
on linux php 4.3.8 there is no error
on windows php 5.0 there is a rounding error, very ugly!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Squinky:
Using your code:
<?PHP
/**
* Convert a number (as a string) in base 10 to any base
*
* e.g. dec2base('32', 16) => '20';
* Uses BCMath extension, so number can be as big as you like
* @param string $value A number in base 10, expressed as a string
* @param integer $base The base to convert to
* @param mixed $digits Optional string representing the characters used in the numbering system
*/
function dec2base($dec, $base, $digits = FALSE) {
if($base < 2 or $base > 256) die("Invalid Base: .$base\n");
bcscale(0);
$value = '';
if(!$digits) $digits = digits($base);
while($dec > $base - 1) {
$rest = bcmod($dec,$base);
$dec = bcdiv($dec,$base);
$value = $digits[$rest].$value;
}
$value=$digits[intval($dec )].$value;
return (string) $value;
}
/**
* Convert a number (as a string) in any base to base 10
*
* e.g. base2dec('20', 16) => '32';
* Uses BCMath extension, so number can be as big as you like
* @param string $value A number in any base, expressed as a string
* @param integer $base the base that this number is in
* @param mixed $digits Optional string representing the characters used in the numbering system
*/
function base2dec($value, $base, $digits = FALSE) {
if($base < 2 or $base > 256) die("Invalid Base: .$base\n");
bcscale(0);
if($base < 37) $value = strtolower($value);
if(!$digits) $digits = digits($base);
$size = strlen($value);
$dec = '0';
for($loop=0; $loop < $size; $loop++) {
$element = strpos($digits, $value[$loop]);
$power = bcpow($base, $size-$loop-1);
$dec = bcadd($dec, bcmul($element, $power));
}
return (string) $dec;
}
/**
* Return a string containing chars to use in a given base's numbering system
*
* e.g. digits(16) => '0123456789abcdef'
* @param integer $base
* @return string
*/
function digits($base) {
if($base > 64) {
$digits = '';
for($loop=0; $loop < $base; $loop++) {
$digits .= chr($loop);
}
} else {
$digits = '0123456789abcdefghijklmno pqrstuvwxy zABCDEFGHI JKLMNOPQRS TUVWXYZ-_' ;
}
$digits = substr($digits, 0, $base);
return (string) $digits;
}
$s = "5555444433331111";
echo "Input#: ".$s;
$encrypt = dec2base($s,36);
echo " <br>Encrypted: ".$encrypt;
$decrypt = base2dec($encrypt,10);
echo " <br>Decrypted: ".$decrypt;
?>
Here are the results:
Input#: 5555444433331111
Encrypt: 1ip8nxua3s7
Decrypt: 10080000307
Did I do something wrong???
Using your code:
<?PHP
/**
* Convert a number (as a string) in base 10 to any base
*
* e.g. dec2base('32', 16) => '20';
* Uses BCMath extension, so number can be as big as you like
* @param string $value A number in base 10, expressed as a string
* @param integer $base The base to convert to
* @param mixed $digits Optional string representing the characters used in the numbering system
*/
function dec2base($dec, $base, $digits = FALSE) {
if($base < 2 or $base > 256) die("Invalid Base: .$base\n");
bcscale(0);
$value = '';
if(!$digits) $digits = digits($base);
while($dec > $base - 1) {
$rest = bcmod($dec,$base);
$dec = bcdiv($dec,$base);
$value = $digits[$rest].$value;
}
$value=$digits[intval($dec
return (string) $value;
}
/**
* Convert a number (as a string) in any base to base 10
*
* e.g. base2dec('20', 16) => '32';
* Uses BCMath extension, so number can be as big as you like
* @param string $value A number in any base, expressed as a string
* @param integer $base the base that this number is in
* @param mixed $digits Optional string representing the characters used in the numbering system
*/
function base2dec($value, $base, $digits = FALSE) {
if($base < 2 or $base > 256) die("Invalid Base: .$base\n");
bcscale(0);
if($base < 37) $value = strtolower($value);
if(!$digits) $digits = digits($base);
$size = strlen($value);
$dec = '0';
for($loop=0; $loop < $size; $loop++) {
$element = strpos($digits, $value[$loop]);
$power = bcpow($base, $size-$loop-1);
$dec = bcadd($dec, bcmul($element, $power));
}
return (string) $dec;
}
/**
* Return a string containing chars to use in a given base's numbering system
*
* e.g. digits(16) => '0123456789abcdef'
* @param integer $base
* @return string
*/
function digits($base) {
if($base > 64) {
$digits = '';
for($loop=0; $loop < $base; $loop++) {
$digits .= chr($loop);
}
} else {
$digits = '0123456789abcdefghijklmno
}
$digits = substr($digits, 0, $base);
return (string) $digits;
}
$s = "5555444433331111";
echo "Input#: ".$s;
$encrypt = dec2base($s,36);
echo " <br>Encrypted: ".$encrypt;
$decrypt = base2dec($encrypt,10);
echo " <br>Decrypted: ".$decrypt;
?>
Here are the results:
Input#: 5555444433331111
Encrypt: 1ip8nxua3s7
Decrypt: 10080000307
Did I do something wrong???
yes:
$decrypt = base2dec($encrypt, 36);
I just happen to have made these functions do conversions to and from base-10, rather than between arbitrary bases. base2dec always produces a base-10 number, but you need to tell it what the input base is. You've got a weird result because you told it that '1ip8nxua3s7' is a base-10 number, and it doesn't check that what you submit is actually a valid number in that base.
$decrypt = base2dec($encrypt, 36);
I just happen to have made these functions do conversions to and from base-10, rather than between arbitrary bases. base2dec always produces a base-10 number, but you need to tell it what the input base is. You've got a weird result because you told it that '1ip8nxua3s7' is a base-10 number, and it doesn't check that what you submit is actually a valid number in that base.
Also, you may want to change the order of upper and lower case letters in the digits function to retain compatibility with your Delphi function - I chose to make lower case numbers represent smaller numbers.
ASKER
I completely took out the capital letters and the - and _, we will never be using a negative number.
I used other routines for the Delphi conversion (see below).
Many thanks.
Delphi code used:
function Base36ToInt(const S: String): Int64;
var
i: integer;
begin
Result := 0;
for i := 1 to Length( S ) do
begin
if S[i] in ['0'..'9'] then
begin
Result := Result * 36 + ( Ord( S[i] ) - Ord( '0' ) );
end
else
begin
Result := Result * 36 + ( Ord(S[i] ) - Ord( 'a' ) + 10);
end;
end;
end;
function IntegerToBase36 (I: Int64): String;
var
N: Int64;
M: integer;
begin
Result := '';
repeat
M := I mod 36;
if M < 10 then
begin
Result := Char( Ord( '0' ) + M ) + Result;
end
else
begin
Result := Char( Ord( 'a' ) + M - 10 ) + Result;
end;
I := I div 36;
until I = 0;
end;
I used other routines for the Delphi conversion (see below).
Many thanks.
Delphi code used:
function Base36ToInt(const S: String): Int64;
var
i: integer;
begin
Result := 0;
for i := 1 to Length( S ) do
begin
if S[i] in ['0'..'9'] then
begin
Result := Result * 36 + ( Ord( S[i] ) - Ord( '0' ) );
end
else
begin
Result := Result * 36 + ( Ord(S[i] ) - Ord( 'a' ) + 10);
end;
end;
end;
function IntegerToBase36 (I: Int64): String;
var
N: Int64;
M: integer;
begin
Result := '';
repeat
M := I mod 36;
if M < 10 then
begin
Result := Char( Ord( '0' ) + M ) + Result;
end
else
begin
Result := Char( Ord( 'a' ) + M - 10 ) + Result;
end;
I := I div 36;
until I = 0;
end;
function Base36ToInt ($s){
static $x=array('1'=>1, '2'=>2, '3'=>3, '4'=>4, '5'=>5, '6'=>6, '7'=>7, '8'=>8, '9'=>9,
'0'=>0, 'a'=>10, 'b'=>11, 'c'=>12, 'd'=>13, 'e'=>14, 'f'=>15, 'g'=>16, 'h'=>18,
'i'=>18, 'j'=>19, 'k'=>20, 'l'=>21, 'm'=>22, 'n'=>23, 'o'=>24, 'p'=>25, 'q'=>26,
'r'=>27, 's'=>28, 't'=>29, 'u'=>30, 'v'=>31, 'w'=>32, 'x'=>33, 'y'=>34, 'z'=>35);
$r=0;
$s=strtolower($s);
for ($i=0;$i<strlen($s);$i++){
$r=bcadd( bcmul($r, 36), $x[$s{$i}]);
}
return $r;
}
echo Base36ToInt('177XYGYLBFLZ4
echo base_convert('177XYGYLBFLZ
result:
5688775099731057664
5688775099731058624