任意进制转换


琢磨着开发一款微博应用吧, 用户至上的原则, 决定让用户传递微博地址过来, 我去分析微博的信息. 然后, 发现微博的地址是/uid/str这样的. 其中str是一串英文数字混合的不算长的字符串. 开始我还不知道这个就是mid. 因为我看接口返回数据的范例中的mid是很长一串数字… 接下来我就开始了62进制转10进制的编程之旅了.

进制转换,这个我就不赘述原理了, 请自行搜索. 简单举例吧. 比如十六进制所有字符为 0123456789abcdef, 当然,是按照小的在前边, 大的在后边排列的. 那么十六进制的a转换成十进制就是10. 直接看的话, 就是从0开始数,第10个是a. 那么十六进制的1a转换成十进制怎么看呢. 先看a,是10. 然后看1. 因为1已经是进位一次后得出来的了,而逢十六才进位一次. 所以,这个1要乘以16. 那么16+10 = 26.也就是1a的十进制结果了. (说不赘述,还墨迹了一下下)

然后, 懂了十六进制与十进制互转. 也就懂了其他进制与十进制的互转了. 比如我们常常用到的0-9a-zA-Z.这一共是62个字符. 也就可以创造出62进制. 这在短域名方面应用的相当恰当. 微博也换成62进制了, 主要原因应该是减少网络传输吧.

上代码:

function s2n($str){
  $x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  $number = 0;
  for ($cnt = strlen($str), $i = $cnt - 1, $p = 0; $i >= 0; --$i, ++$p) { 
    $number += strpos($x, $str[$i]) * pow(62, $p);
  }
  return $number;
}

function n2s($number){
  $x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  $str = '';
  do {
    $p = $number > PHP_INT_MAX ?  intval(bcmod($number, 62)) : intval($number % 62);
    $str = $x[$p] . $str;
    if (($number = $number / 62) < 62){
      $str = $x[intval($number)] . $str;
      break;
    }
  }while (true);
  return $str;
}
ini_set('precision', 30); //浮点数显示精度 读鸟哥博客发现的
$str = 'zbRaBuwmp';
$number = s2n($str);
echo $number, PHP_EOL;
echo n2s($number);

需要注意的地方就是, 如果你的进制数大于你的系统位数. 那么就悲剧了. 所以, 采用bcmath相关的函数. 具体怎么悲剧的. 我赶脚程序猿们应该自己试一试, 结果会让你记的更深刻.


发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注