【问题标题】:PHP - How to base_convert() up to base 62PHP - 如何将 base_convert() 转换为基数 62
【发布时间】:2010-12-28 14:59:16
【问题描述】:

我需要一个base_convert() 函数,它的工作范围从 2 到 62,但我缺少我需要使用的数学,我知道由于 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;
}

谁能解释一下上面的函数,或者给我一些关于任意基之间直接转换的过程?

【问题讨论】:

    标签: php math base-conversion base62


    【解决方案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
    

    【讨论】:

      【解决方案2】:

      我在互联网上找到的大多数示例以及此答案中的示例都使用了 BC 数学函数。如果你不想使用使用 BC 数学函数,你可以看看这个库: http://www.lalit.org/lab/base62-php-convert-number-to-base-62-for-short-urls/

      • 它不使用 BC Math 函数,因此无需使用 BC Math 即可工作 图书馆。
      • 当基数低于 36 时,它使用本机 base_convert 函数以加快执行速度。
      • 输出数字向后兼容原生 base_convert 函数。
      • 可用于与 2-64 之间的任意基数进行转换。

      【讨论】:

        【解决方案3】:

        从 PHP 5.3.2 开始,bc_math 和 gmp 现在都支持高达 62 的基数,因此您可以这样做:

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

        或等效的 bc_math。

        【讨论】:

        • 很高兴知道,但是我找不到 BC 数学等价物。
        • base_convert() 不允许到 base 62
        • 无耻的自我插件,我写了一个使用 GMP 处理任意数字和基数的实用程序,来源在 GitHub 上:github.com/thunderer/Numbase
        【解决方案4】:

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

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

        【讨论】:

        • 对于超过 62 个字符的限制非常有用!
        • 经过几天的搜索如何转换数字字符串(因为 PHP 将 bigint 解析为浮点数并变得不精确),这个函数也可以进行反向转换。例如。将$number = "1255276776369394619"; 转换为b4JlnAoHP37,反之亦然。太好了!
        【解决方案5】:

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

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

        (您也可以创建一个在一次调用中完成的组合函数。)

        【讨论】:

        • 请注意,base_convert() 本身 - 在内部 - 使用中间基础,正如我在此处指出的那样:exploringbinary.com/…
        【解决方案6】:

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

        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.13 但 0.333...10,而 1/1010 是 .0001100110011...2)。

        关于转换工作原理的一般解释,请考虑positional base systems 的工作原理。 anan-1...a1a0 形式的数字base b 代表数字“an*bn + an-1*bn -1 + ... + a1*b1 + a0*b0 ”。转换基本上是通过在另一个基础 β 的上下文中评估表达式来实现的。

        【讨论】:

        • 对不起,我不明白,你的意思是我不能直接从base 61转换为base 5?
        • 可以,但是使用平台原生格式作为中间形式会更容易。
        猜你喜欢
        • 2011-06-25
        • 1970-01-01
        • 2010-11-10
        • 1970-01-01
        • 2010-09-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多