PHP - 如何将base_convert()扩展到62

时间:2009-12-21 03:34:37

标签: php math base-conversion base62

我需要一个{base}到base 62的base_convert()函数,但是我错过了我需要使用的数学,我知道由于PHP的限制,我需要使用bcmath,这很好。

函数like these将数字转换为基数10到另一个基数最多为62,但我想实现base_convert()的相同功能,例如:只有一个函数可以在任意之间进行转换碱基。

我找到了一个function that seems to do this,但它给了我一些冗余和慢速代码的感觉,如果我认识德语,我想稍微调整一下,我不知道。 =(

这是一个更易读的函数版本:

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 个答案:

答案 0 :(得分:12)

从PHP 5.3.2开始,bc_math和gmp现在都支持最多62个,所以你可以这样做:

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

或bc_math当量。

答案 1 :(得分:8)

请不要问我从哪里得到它,我只记得它是基于我在网上找到的一些例子......

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

答案 2 :(得分:1)

从数字库到人类语言的任何翻译问题最简单的方法是通过中间格式进行翻译。

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

现在您需要写的只有bc_convert_tobc_parse_num。如果平台区分数字类型,则需要将其考虑在内。此外,浮点数需要特别考虑因为一个数字可能在一个基数中具有有限的表示,但不是另一个(例如1/3是0.1 3 但是0.333 ... 10 ,和1/10 10 是.0001100110011 ... 2 )。

关于转化如何运作的一般化解释,请考虑positional base systems的工作原理。形式为“a n a n-1 ... a 1 a 0 ”的数字base b 表示数字“a n * b n + a n-1 * b n -1 + ... + a 1 * b 1 + a 0 * b 0 ”。转换基本上通过评估另一个基础β的上下文中的表达来起作用。

答案 3 :(得分:1)

我在互联网上找到的大多数例子都是使用BC Math函数。如果您不想使用BC Math函数,可以查看此库: http://www.lalit.org/lab/base62-php-convert-number-to-base-62-for-short-urls/

  • 它不使用BC Math函数,因此无需使用BC Math即可工作 库。
  • 当base低于36时,它使用本机base_convert函数,以便更快地执行。
  • 输出编号与本机base_convert函数向后兼容。
  • 可用于在2-64之间转换为任意碱基。

答案 4 :(得分:0)

我在这里写了关于使用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,将数字余数转换为/来自字符基数,并重命名变量。

现在,要在任意碱基之间进行转换,请使用decimal作为中间函数并调用这两个新函数。例如,通过调用$ dec = base2dec_i('42','123')然后$ b59 = dec2base_i(59,$ dec)将base 42 number“123”转换为base 59。

(你也可以在一次通话中制作组合功能。)

答案 5 :(得分:-1)

如果可能,此函数输出的内容与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