conversion d'un nombre de base 10 en base 62 (A-zA-Z0-9)
J'ai un numéro en base 10. Y a-t-il de toute façon pour le traduire en base 62?
Exemple:
echo convert(12324324);
// returns Yg3 (fantasy example here)
PHP base_convert()
peut convertir jusqu'à base 36.
9 réponses
VIEUX - : UN rapide et sale solution peut être d'utiliser une fonction comme ceci:
function toChars($number) {
$res = base_convert($number, 10,26);
$res = strtr($res,'0123456789','qrstuvxwyz');
return $res;
}
La base convertir traduire votre nombre à une base où les chiffres sont 0-9a-p ensuite, vous vous débarrassez des chiffres restants avec une substitution de caractères rapide.
Comme vous pouvez le constater, la fonction est facilement réversible.
function toNum($number) {
$res = strtr($number,'qrstuvxwyz','0123456789');
$res = base_convert($number, 26,10);
return $res;
}
Au fait, à quoi utiliseriez-vous cette fonction?
Modifier:
Basé sur le changement de question et sur la réponse @jnpcl, voici un ensemble de fonctions qui effectue la conversion de base sans utiliser pow et log (ils prennent la moitié du temps pour terminer les tests).
Les fonctions ne fonctionnent que pour les valeurs entières.
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;
}
Le test:
for ($i = 0; $i<1000000; $i++) {
$x = toBase($i);
$y = to10($x);
if ($i-$y)
echo "\n$i -> $x -> $y";
}
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;
}
?>
Paramètres:
$num
- votre entier décimal
$base
- de base que vous souhaitez convertir$num
(laissez 0 si vous fournissez$index
, ou omettre si vous utilisez la valeur par défaut (62))
$index
- Si vous souhaitez utiliser la liste de chiffres par défaut (0-1a-zA-Z), omettez cette option, sinon fournissez une chaîne (ex.: "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;
}
?>
Paramètres:
$num
- votre numéro personnalisé (chaîne) (ex.: "11011101")
$base
- base$num
a été codée (laissez 0 si vous fournissez$index
, ou omettre si vous utilisez par défaut (62))
$index
- Si vous souhaitez utiliser la liste de chiffres par défaut (0-1a-zA-Z), omettez cette option, sinon fournissez une chaîne (ex.: "abcdef")
Pour les grands nombres, vous pouvez utiliser la bibliothèque 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;
}
Une implémentation plus simple (et peut-être plus rapide) qui n'utilise pas pow
Ni log
:
function base62($num) {
$index = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$res = '';
do {
$res = $index[$num % 62] . $res;
$num = intval($num / 62);
} while ($num);
return $res;
}
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;
}
Cette fonction produit la même chose que GNU Multiple Precision si possible ...
<?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
Ont un tableau de caractères comme:
$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);
}
Il a été à peine testé et fonctionne sur de vrais gros produits. Il suffit de copier ces fonctions et utiliser. si nécessaire, vous pouvez organiser $ baseChars séquentiellement, j'en ai besoin pour blended.
/**
* 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éthode inverse
/**
* 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;
}
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;
}