php - number - convertir una base numérica 10 en una base 62(a-zA-Z0-9)
php binary to string (9)
Tengo un número en la base 10. ¿Hay alguna forma de traducirlo a una base 62?
Ejemplo:
echo convert(12324324);
// returns Yg3 (fantasy example here)
PHP base_convert()
puede convertir hasta la base 36.
Apenas fue probado y funciona en un producto realmente grande. Solo copia estas funciones y usa. Si es necesario, puede organizar $ baseChars secuencialmente, lo necesito para mezclar.
/**
* decToAny converter
*
* @param integer $num
* @param string $baseChars
* @param integer $base
* @return string
*/
function decToAny($num, $baseChars = '''', $base = 62, $index = false) {
$baseChars = empty($baseChars) ? ''HbUlYmGoAd0ScKq6Er5PuZp3OsQCh4RfNMtV8kJiLv9yXeI1aWgFj2zTx7DnBw'' : $baseChars;
if (!$base) {
$base = strlen($index);
} else if (!$index) {
$index = substr($baseChars, 0, $base);
}
$out = "";
for ($t = floor(log10($num) / log10($base)); $t >= 0; $t--) {
$a = floor($num / pow($base, $t));
$out = $out . substr($index, $a, 1);
$num = $num - ( $a * pow($base, $t) );
}
return $out;
}
Método inverso
/**
* anyTodec converter
*
* @param string $num
* @param string $baseChars
* @param integer $base
* @return string
*/
function anyToDec($num, $baseChars = '''', $base = 62, $index = false) {
$baseChars = empty($baseChars) ? ''HbUlYmGoAd0ScKq6Er5PuZp3OsQCh4RfNMtV8kJiLv9yXeI1aWgFj2zTx7DnBw'' : $baseChars;
if (!$base) {
$base = strlen($index);
} else if (!$index) {
$index = substr($baseChars, 0, $base);
}
$out = 0;
$len = strlen($num) - 1;
for ($t = 0; $t <= $len; $t++) {
$out = $out + strpos($index, substr($num, $t, 1)) * pow($base, $len - $t);
}
return $out;
}
Esta función tiene la misma salida que GNU Precisión múltiple, si es posible ...
<?php
function base_convert_alt($val,$from_base,$to_base){
static $gmp;
static $bc;
static $gmp62;
if ($from_base<37) $val=strtoupper($val);
if ($gmp===null) $gmp=function_exists(''gmp_init'');
if ($gmp62===null) $gmp62=version_compare(PHP_VERSION,''5.3.2'')>=0;
if ($gmp && ($gmp62 or ($from_base<37 && $to_base<37)))
return gmp_strval(gmp_init($val,$from_base),$to_base);
if ($bc===null) $bc=function_exists(''bcscale'');
$range=''0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'';
if ($from_base==10)
$base_10=$val;
else
{
$n=strlen(($val="$val"))-++$ratio;
if ($bc) for($i=$n;$i>-1;($ratio=bcmul($ratio,$from_base)) && $i--)
$base_10=bcadd($base_10,bcmul(strpos($range,$val[$i]),$ratio));
else for($i=$n;$i>-1;($ratio*=$from_base) && $i--)
$base_10+=strpos($range,$val[$i])*$ratio;
}
if ($bc)
do $result.=$range[bcmod($base_10,$to_base)];
while(($base_10=bcdiv($base_10,$to_base))>=1);
else
do $result.=$range[$base_10%$to_base];
while(($base_10/=$to_base)>=1);
return strrev($to_base<37?strtolower($result):$result);
}
echo base_convert_alt(''2661500360'',7,51);
// Output Hello
Para números grandes, es posible que desee utilizar la biblioteca de PHP BC
function intToAny( $num, $base = null, $index = null ) {
if ( $num <= 0 ) return ''0'';
if ( ! $index )
$index = ''0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'';
if ( ! $base )
$base = strlen( $index );
else
$index = substr( $index, 0, $base );
$res = '''';
while( $num > 0 ) {
$char = bcmod( $num, $base );
$res .= substr( $index, $char, 1 );
$num = bcsub( $num, $char );
$num = bcdiv( $num, $base );
}
return $res;
}
Una implementación más simple (y posiblemente más rápida) que no usa pow
ni log
:
function base62($num) {
$index = ''0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'';
$res = '''';
do {
$res = $index[$num % 62] . $res;
$num = intval($num / 62);
} while ($num);
return $res;
}
tener una serie de caracteres como:
$chars = array(
1 => ''a'',
2 => ''b'',
//....
27 => ''A'',
28 => ''B''
);
function getCharacter($key)
{
if(array_key_exists($key, $chars[$key]))
return $chars[$key];
return false;
}
function getNumber($char)
{
return array_search($char, $chars);
}
http://us3.php.net/manual/en/function.base-convert.php#52450
<?php
// Decimal > Custom
function dec2any( $num, $base=62, $index=false ) {
if (! $base ) {
$base = strlen( $index );
} else if (! $index ) {
$index = substr( "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ,0 ,$base );
}
$out = "";
// this fix partially breaks when $num=0, but fixes the $num=238328 bug
// also seems to break (adds a leading zero) at $num=226981 through $num=238327 *shrug*
// for ( $t = floor( log10( $num ) / log10( $base - 1 ) ); $t >= 0; $t-- ) {
// original code:
for ( $t = floor( log10( $num ) / log10( $base ) ); $t >= 0; $t-- ) {
$a = floor( $num / pow( $base, $t ) );
$out = $out . substr( $index, $a, 1 );
$num = $num - ( $a * pow( $base, $t ) );
}
return $out;
}
?>
Parámetros:
$num
- tu entero decimal
$base
- base a la que desea convertir$num
(déjelo 0 si está proporcionando$index
u omita si está usando el valor predeterminado (62))
$index
: si desea usar la lista de dígitos predeterminada (0-1a-zA-Z), omita esta opción, de lo contrario, proporcione una cadena (ej .: "zyxwvu")
<?php
// Custom > Decimal
function any2dec( $num, $base=62, $index=false ) {
if (! $base ) {
$base = strlen( $index );
} else if (! $index ) {
$index = substr( "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 0, $base );
}
$out = 0;
$len = strlen( $num ) - 1;
for ( $t = 0; $t <= $len; $t++ ) {
$out = $out + strpos( $index, substr( $num, $t, 1 ) ) * pow( $base, $len - $t );
}
return $out;
}
?>
Parámetros:
$num
- su número personalizado (cadena) (ej .: "11011101")
$base
- base con la que se codificó$num
(déjelo 0 si está proporcionando$index
u omita si está usando el valor predeterminado (62))
$index
: si desea usar la lista de dígitos predeterminada (0-1a-zA-Z), omita esta opción, de lo contrario, proporcione una cadena (ej .: "abcdef")
ANTIGUO : Una solución rápida y sucia puede ser usar una función como esta:
function toChars($number) {
$res = base_convert($number, 10,26);
$res = strtr($res,''0123456789'',''qrstuvxwyz'');
return $res;
}
La conversión de base convierte su número a una base donde los dígitos son 0-9a-p y luego elimina los dígitos restantes con una rápida sustitución de caracteres.
Como puede observar, la función es fácilmente reversible.
function toNum($number) {
$res = strtr($number,''qrstuvxwyz'',''0123456789'');
$res = base_convert($number, 26,10);
return $res;
}
Por cierto, ¿para qué usarías esta función?
Editar:
Basado en el cambio de la pregunta y en la respuesta de @jnpcl, aquí hay un conjunto de funciones que realizan la conversión básica sin usar pow y log (toman la mitad del tiempo para completar las pruebas).
Las funciones funcionan solo para valores enteros.
function toBase($num, $b=62) {
$base=''0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'';
$r = $num % $b ;
$res = $base[$r];
$q = floor($num/$b);
while ($q) {
$r = $q % $b;
$q =floor($q/$b);
$res = $base[$r].$res;
}
return $res;
}
function to10( $num, $b=62) {
$base=''0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'';
$limit = strlen($num);
$res=strpos($base,$num[0]);
for($i=1;$i<$limit;$i++) {
$res = $b * $res + strpos($base,$num[$i]);
}
return $res;
}
La prueba:
for ($i = 0; $i<1000000; $i++) {
$x = toBase($i);
$y = to10($x);
if ($i-$y)
echo "/n$i -> $x -> $y";
}
function convertBase10ToBase62($num){
$charset="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$endChar=$charset[$num%62];
$rtn="";
if ( $num == "62" ) {
$rtn=$rtn.$charset[1];
} else if ( $num >= 62 ) {
$rtn=$rtn.$charset[intval($num/62)%62+1];
}
$num=intval($num/62);
while ($num > 61) {
if ( is_int($num/62) == true ) {
$rtn=$rtn.$charset[0];
} else {
$rtn=$rtn.$charset[$num%62];
}
$num=intval($num/62);
}
$rtn=$rtn.$endChar;
echo "/n";
echo $rtn;
return $rtn;
}
function convertBase10ToBase62($num){
$charset="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$rtn="";
$n=$num;$base=62;
while($n>0){
$temp=$n%$base;
$rtn=$charset[$temp].$rtn;
$n=intval($n/$base);
}
return $rtn;
}