PHP - come base_convert () fino alla base 62
-
20-09-2019 - |
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?
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