PHP - Как base_convert () до базы 62 - PullRequest
7 голосов
/ 21 декабря 2009

Мне нужна функция base_convert(), которая работает от базы 2 до базы 62, но мне не хватает математики, которую мне нужно использовать, я знаю, что из-за ограничений PHP мне нужно использовать bcmath, который хорошо.

Функции , подобные этим , преобразуют число в и из базы 10 в другую базу до 62, но я хочу реализовать ту же функциональность, что и base_convert(), например: только одна функция, которая может преобразовывать произвольные основания.

Я нашел функцию, которая, кажется, делает это , но она дает мне ощущение наличия некоторого избыточного и медленного кода, и я хотел бы немного его настроить, если бы я знал немецкий, который Я не. = (

Вот более читаемая версия функции:

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;
}

Может кто-нибудь объяснить мне вышеупомянутую функцию или дать мне некоторое представление о процессе прямого преобразования между произвольными базами?

Ответы [ 6 ]

12 голосов
/ 10 августа 2011

Начиная с PHP 5.3.2, bc_math и gmp теперь поддерживают базы до 62, поэтому вы можете просто сделать:

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

или эквивалент bc_math.

8 голосов
/ 12 января 2011

Пожалуйста, не спрашивайте меня, откуда я его взял, я просто помню, что он основан на некоторых примерах, которые я нашел в Интернете ...

  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;
  }
1 голос
/ 08 декабря 2011

Большинство примеров, которые я нашел в Интернете и в этих ответах, используют функции BC Math. Если вы не хотите использовать функции BC Math, вы можете взглянуть на эту библиотеку: http://www.lalit.org/lab/base62-php-convert-number-to-base-62-for-short-urls/

  • Он не использует функции BC Math, поэтому работает без использования BC Math. библиотека.
  • Он использует встроенные функции base_convert, когда основание ниже 36 для более быстрого выполнения.
  • Выходной номер обратно совместим с собственной функцией base_convert.
  • Может использоваться для преобразования в и из произвольных базисов между 2-64.
1 голос
/ 21 декабря 2009

Самый простой подход для любых задач перевода, от числовой базы до человеческих языков, - это перевод через промежуточный формат.

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

Теперь все, что вам нужно написать, это bc_convert_to и bc_parse_num. Если платформа различает числовые типы, вам необходимо принять это во внимание. Кроме того, числа с плавающей запятой требуют особого рассмотрения, потому что число может иметь конечное представление в одной базе, но не в другом (например, 1/3 - это 0,1 3 , но 0,333 ... 10 , и 1/10 10 составляет .0001100110011 ... 2 ).

Что касается обобщенного объяснения того, как работает преобразование, рассмотрим, как позиционные базовые системы работают. Цифра вида "a n a n-1 ... a 1 a 0 " в основании b представляет число "a n * b n + a n-1 * b n-1 + .. . + a 1 * b 1 + a 0 * b 0". Преобразование в основном работает путем оценки выражения в контексте другой базы & beta;.

0 голосов
/ 08 марта 2017

Эта функция выводит то же, что и GNU Multiple Precision , если это возможно ...

<?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
0 голосов
/ 21 декабря 2009

Я писал об использовании функций BCMath для десятичного / двоичного преобразования здесь: http://www.exploringbinary.com/base-conversion-in-php-using-bcmath/. Вы можете легко изменить этот код для преобразования в другие базы.

Например, в случае преобразования целых чисел измените подпрограммы dec2bin_i () и bin2dec_i (). Переименуйте их и добавьте базовый параметр - что-то вроде dec2base_i ($ base, $ decimal_i) и base2dec_i ($ base, $ num_i), измените жестко закодированный '2' на переменную $ base, преобразуйте числовые остатки в символы из / из базы и переименуйте переменные.

Теперь, чтобы преобразовать произвольную базу, используйте десятичную в качестве промежуточного и вызовите обе эти новые функции. Например, преобразуйте базовое число 42 «123» в базовое 59, вызвав $ dec = base2dec_i ('42 ',' 123 '), а затем $ b59 = dec2base_i (59, $ dec).

(Вы также можете создать комбинированную функцию, которая делает это за один вызов.)

...