如何压缩一个非常大的数字到字母数字(在PHP中)?

k4aesqcs  于 2023-01-12  发布在  PHP
关注(0)|答案(4)|浏览(198)

我想把一个很大的数字压缩成字母数字[0-9a-zA-Z]。当然,最简单的方法是使用一个内置的php函数base64_encode(),但是我很讨厌这个方法,它会产生额外的字符,比如“/”和“=”。更重要的是,base64_encode对压缩数字没有任何作用,因为这个函数把数字当作字符串。
我曾经考虑过另一个内置函数'base_convert()',但它只能将数字转换为字符集[0-9a-z],使结果更长。
我现在用一种廉价的方式来实现我的目标:

function compress_int($num) {
    $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

    $result = '';

    while( $num ) {
        $mod = $num % 52;
        $num = intval($num / 52);

        $result .= $chars[$mod];
    }

    return $result;
}

然而,我认为这是非常低效的。所以我非常感谢谁能告诉我一个更好的方法与更高的效率。

ldfqzlk8

ldfqzlk81#

这是我以前为一个c++应用程序做的一个例子,欢迎使用。

// $num - the number we want to convert
// $symbols - the chars you want to use e.g. '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
// &$out is a pointer to your $result
function intToBase($num, $symbols, &$out){
    
    // get the radix that we are working with
    $radix = strlen($symbols);
    
    $pos = strlen($out)-1;
    
    if($num==0){
        // if our number is zero then we can just use the first character of our symbols and we are done.
        $out[$pos] = $symbols[0];
    }else{
        // otherwise we have to loop through and rebase the integer one character at a time.
        while ($num > 0) {
            // split off one digit
           $r = $num % $radix;
            // convert it and add it to the char array
            $out[$pos] = $symbols[$r];
            // subtract what we have added to the compressed string
            $num = ($num - $r) / $radix;
            $pos--;
        }
    }
};

简单地使用:

$num = 123004954712; //whatever number you want to compress
$result = "";// the result variable we will be writing to
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';// the caracters of our custom base.
intToBase($num, $chars, $result);// the call
// now our $result variable will have the rebased string.
rt4zxlrg

rt4zxlrg2#

为了补充Goran的答案,保存一些人的时间,下面是一个函数,它可以在转换后将int值返回给用户:

function baseToInt($base, $symbols, &$out) {
    //get length of the char map, so you can change according to your needs
    $radix = strlen($symbols);

    //split the chars into an array and initialize variables
    $arr = str_split($base,1);
    $i = 0;
    $out = 0;

    //loop through each char assigning values
    //chars to the left are the least significant
    foreach($arr as $char) {
        $pos = strpos($symbols, $char);
        $partialSum = $pos * pow($radix, $i);
        $out += $partialSum;
        $i++;
    }
}

电话和Goran的一模一样

$number = 123456;
$symbols = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

$strBase = "";
intToBase($number, $symbols, $strBase);

$intReturn = 0;
baseToInt($strBase, $symbols , $intReturn);

echo $strBase."<br>"; //e7w
echo $intReturn; //123456
tvmytwxo

tvmytwxo3#

Goran的回答是完全正确的,但多年来PHP变得更加严格,并已略有改变的使用参考,所以要更新到今天的时间,我们可以用途:

function intToBase(int $num)
{
    $symbols = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    // get the radix that we are working with
    $radix = strlen($symbols);
    $out   = [];
    if ($num === 0) {
        // if our number is zero then we can just use the first character of our symbols and we are done.
        return $symbols[0];
    }
    // otherwise we have to loop through and rebase the integer one character at a time.
    while ($num > 0) {
        // split off one digit
        $r = $num % $radix;
        // convert it and add it to the char array
        array_unshift($out, $symbols[$r]);
        // subtract what we have added to the compressed string
        $num = (int)floor(($num - $r) / $radix);
    }

    return implode('', $out);
}

此版本将使用严格类型。

t3irkdon

t3irkdon4#

基于上述算法,我已经修复了它的工作非常长的数字,以及使用GMP .它有点更有效的代码,并共享编码/解码方式:

function intToBase(int|string $num)
{
    // sometimes $num is sent using gmt_intval which of type string on very very large numbers                                                                     
    if ( ! is_numeric($num) ) return 0;
    $symbols = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    // get the radix that we are working with
    $radix = strlen($symbols);
    $out   = [];
    if ($num === 0) { 
        // if our number is zero then we can just use the first character of our symbols and we are done.
        return $symbols[0];
    }    
    // otherwise we have to loop through and rebase the integer one character at a time.
    while ($num > 0) { 
        // split off one digit
        $r = (int) gmp_div_r ($num, $radix);  // $num % $radix
        // convert it and add it to the char array
        $out[] = $symbols[$r];
        // subtract what we have added to the compressed string
        $num = gmp_div ( gmp_sub($num, $r), $radix); // ($num-$r) / $radix
    }    
    return implode('', array_reverse($out));
}

function baseToInt($base) {
    $symbols = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    //get length of the char map, so you can change according to your needs
    $radix = strlen($symbols);

    //split the chars into an array and initialize variables
    $arr = str_split($base,1);
    $out = 0;

    //loop through each char assigning values
    //chars to the left are the least significant
    foreach($arr as $char) {
        $pos = strpos($symbols, $char);
        $out = gmp_add ( gmp_mul ($out,$radix), $pos);  //  ($out*radix) + $pos
    }                                                                                                                                                              
    return $out;
}

相关问题