web-dev-qa-db-fra.com

conversion d'une base numérique 10 en base 62 (a-zA-Z0-9)

J'ai un nombre en base 10. Est-il possible de le traduire en base 62?

Exemple:

echo convert(12324324);
// returns Yg3 (fantasy example here)

PHP base_convert() peut convertir jusqu'à la base 36.

28
dynamic

OLD : Une solution rapide et sale peut être d'utiliser une fonction comme celle-ci:

function toChars($number) {
   $res = base_convert($number, 10,26);
   $res = strtr($res,'0123456789','qrstuvxwyz');
   return $res;
}

La conversion de base traduit votre numéro en une base où les chiffres sont 0-9a-p, puis 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:

Sur la base du changement de question et de la réponse @jnpcl, voici un ensemble de fonctions qui effectue la conversion de base sans utiliser pow et log (elles prennent la moitié du temps pour terminer les tests).

Les fonctions fonctionnent uniquement 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";
}
36
Eineki

http://us3.php.net/manual/en/function.base-convert.php#5245

<?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 - base dans laquelle vous souhaitez convertir $num (laissez 0 si vous fournissez $index ou omis 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 avec laquelle $num a été encodé (laissez-le 0 si vous fournissez $index ou omis 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 .: "abcdef")

7
drudge

Cette fonction génère 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
3
Php'Regex

Une implémentation plus simple (et peut-être plus rapide) qui n'utilise ni pow ni log:

function base62($num) {
  $index = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  $res = '';
  do {
    $res = $index[$num % 62] . $res;
    $num = intval($num / 62);
  } while ($num);
  return $res;
}
3
instanceof me

Pour les grands nombres, vous voudrez peut-être 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;
}
3
ukautz
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;
}
2
Doug

Il a été à peine testé et fonctionne sur de très gros produits. Copiez simplement ces fonctions et utilisez-les. Si nécessaire, vous pouvez organiser séquentiellement $ baseChars, j'en ai besoin pour le mélange.

    /**
     * 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;
    }
1
Tigran Babajanyan

avoir 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);
}
1
Patrick
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;
}
0
sfg2k

Si vous avez l'extension gmp:

gmp_strval(gmp_init($x, 10), 62)
0
Vladislav Ross