Domanda

ho bisogno di un base_convert() Funzione che funziona dalla base 2 fino alla base 62 ma mi manca la matematica che devo usare, so che a causa dei limiti di PHP ho bisogno di utilizzare BCMath, il che va bene.

Funzioni come questi convertire un numero da e verso la base 10 a un'altra base fino a 62, ma voglio implementare la stessa funzionalità di base_convert(), EG: una sola funzione che può convertire tra basi arbitrarie.

Ho trovato un funzione che sembra farlo, ma mi dà la sensazione di avere un codice ridondante e lento e vorrei modificarlo un po 'se conoscessi il tedesco, cosa che non faccio. = (

Ecco una versione più leggibile della funzione:

function bc_base_convert($value, $quellformat, $zielformat)
{
    $vorrat = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

    if (min($quellformat, $zielformat) < 2)
    {
        trigger_error('Bad Format min: 2', E_USER_ERROR);
    }

    if (max($quellformat, $zielformat) > strlen($vorrat))
    {
        trigger_error('Bad Format max: ' . strlen($vorrat), E_USER_ERROR);
    }

    $dezi = '0';
    $level = 0;
    $result = '';
    $value = trim(strval($value), "\r\n\t +");
    $vorzeichen = '-' === $value{0} ? '-' : '';
    $value = ltrim($value, "-0");
    $len = strlen($value);

    for ($i = 0; $i < $len; $i++)
    {
        $wert = strpos($vorrat, $value{$len - 1 - $i});

        if (FALSE === $wert)
        {
            trigger_error('Bad Char in input 1', E_USER_ERROR);
        }

        if ($wert >= $quellformat)
        {
            trigger_error('Bad Char in input 2', E_USER_ERROR);
        }

        $dezi = bcadd($dezi, bcmul(bcpow($quellformat, $i), $wert));
    }

    if (10 == $zielformat)
    {
        return $vorzeichen . $dezi; // abkürzung
    }

    while (1 !== bccomp(bcpow($zielformat, $level++), $dezi));

    for ($i = $level - 2; $i >= 0; $i--)
    {
        $factor = bcpow($zielformat, $i);
        $zahl = bcdiv($dezi, $factor, 0);
        $dezi = bcmod($dezi, $factor);
        $result .= $vorrat{$zahl};
    }

    $result = empty($result) ? '0' : $result;

    return $vorzeichen . $result;
}

Qualcuno può spiegarmi la funzione di cui sopra o darmi alcune luci sul processo di conversione diretta tra basi arbitrarie?

È stato utile?

Soluzione

A partire da PHP 5.3.2 Sia BC_Math che GMP ora supportano le basi fino a 62, quindi puoi solo fare:

echo gmp_strval(gmp_init($mynumber, $srcbase), $destbase);

o l'equivalente BC_Math.

Altri suggerimenti

Per favore, non chiedermi da dove l'ho preso, mi ricordo solo che si basa su alcuni esempi che ho trovato sul web ...

  function charset_base_convert ($numstring, $fromcharset, $tocharset) {
     $frombase=strlen($fromcharset);
     $tobase=strlen($tocharset);
     $chars = $fromcharset;
     $tostring = $tocharset;

     $length = strlen($numstring);
     $result = '';
     for ($i = 0; $i < $length; $i++) {
         $number[$i] = strpos($chars, $numstring{$i});
     }
     do {
         $divide = 0;
         $newlen = 0;
         for ($i = 0; $i < $length; $i++) {
             $divide = $divide * $frombase + $number[$i];
             if ($divide >= $tobase) {
                 $number[$newlen++] = (int)($divide / $tobase);
                 $divide = $divide % $tobase;
             } elseif ($newlen > 0) {
                 $number[$newlen++] = 0;
             }
         }
         $length = $newlen;
         $result = $tostring{$divide} . $result;
     }
     while ($newlen != 0);
     return $result;
  }

L'approccio più semplice per eventuali problemi di traduzione, dalla base numerica alle lingue umane, è tradurre attraverso un formato intermedio.

function bc_base_convert($num, $from, $to) {
    return bc_convert_to(bc_parse_num($num, $from), $to);
}

Ora tutto ciò che devi scrivere sono bc_convert_to e bc_parse_num. Se la piattaforma distingue i tipi numerici, dovrai accettare questo. Inoltre, i numeri dei punti galleggianti richiedono una considerazione speciale perché un numero può avere una rappresentazione finita in una base, ma non un'altra (ad esempio 1/3 è 0,13 Ma 0.333 ...10, e 1/1010 è .0001100110011 ...2).

Per quanto riguarda una spiegazione generalizzata di come funziona la conversione, considera come sistemi di base posizionale opera. Un numero della forma "anunN-1...un1un0"In una base b rappresenta il numero "an*bn + aN-1*bN-1 + ... + a1*b1 + a0*b0". La conversione funziona sostanzialmente valutando l'espressione nel contesto di un'altra base β.

La maggior parte degli esempi che ho trovato su Internet e in queste risposte utilizzano le funzioni matematiche BC. Se non si desidera utilizzare le funzioni matematiche BC, puoi dare un'occhiata a questa libreria:http://www.lalit.org/lab/base62-php-convert-number-to-base-62-for-short-urls/

  • Non utilizza le funzioni matematiche BC, quindi funziona senza l'uso della biblioteca matematica BC.
  • Utilizza le funzioni native Base_Convert quando la base è inferiore a 36 per un'esecuzione più veloce.
  • Il numero di output è compatibile all'indietro con la funzione Base_Convert nativa.
  • Può essere usato per convertire da e verso basi arbitrarie tra 2-64.

Ho scritto sull'uso delle funzioni BCMath per la conversione decimale/binaria qui: http://www.exploringbinary.com/base-conversion-in-php-using-bcmath/ . È possibile modificare facilmente quel codice per convertire in basi diverse.

Ad esempio, nel caso della conversione di numeri interi, modificare le routine DeC2bin_i () e bin2dec_i (). Rinominali e aggiungi un parametro di base - qualcosa come Dec2Base_i ($ Base, $ decimal_i) e Base2Dec_i ($ Base, $ Num_i), modifica il codifica hard "2" alla variabile $ Base, convertono i resti numerici in/da personaggi la base e rinominare le variabili.

Ora, per convertirsi tra basi arbitrarie, utilizzare il decimale come intermedio e chiamare entrambe queste nuove funzioni. Ad esempio, convertire la base 42 numero "123" in base 59 chiamando $ dec = base2dec_i ('42 ',' 123 ') seguito da $ b59 = dec2base_i (59, $ dec).

(Potresti anche fare una funzione combinata che lo fa in una chiamata.)

Questa funzione emette allo stesso modo di GNU Precisione multipla se possibile…

<?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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top