个人随笔
目录
手写Java十进制和六十四进制互相转换工具类
2019-08-16 23:08:02

关键字:十进制、十六进制、进制转换、短连接

1、背景

有时候,比如我们的链接可能太长了,此时可以考虑用短连接的方式来,比如链接

https://www.suibibk.com/blog/579412311547052032/555875030676799488/611887075330883584

这种链接生成二维码后,密度太高,有点都不方便,此时我们可以将其用hash后产生一个摘要,然后同时用雪花算法生成一个19位的数字,对生成的十九位的数字进行64进制转换(这里建议62进制,因为64进制会加上+,-这些特殊字符,链接中不友好),然后和原url一起放入数据库中。那么页面访问就可以是

https://www.suibibk.com/short/JcEurLBHed

生成的二维码密度也比较低啦。用户访问就直接访问上面的链接,然后后台根据JcEurLBHed去数据库找出原链接重定向即可。

2、原理:

好了,其实原理很简单,主要是我们得有十进制十六进制的转换工具类,其实只要知道原理就很好写了,原理可以参考我的博文:进制转换详解

X进制转十进制:
X进制数从低位到高位(即从右往左)计算,第0位的权值是X的0次方,第1位的权值是X的1次方,第2位的权值是X的2次方,依次递增下去,把最后的结果相加的值就是十进制的值了。

十进制转X进制:
除X取余法,即每次将整数部分除以X,余数为该位权上的数,而商继续除以X,余数又为上一个位权上的数,这个步骤一直持续下去,直到商为0为止,最后读数时候,从最后一个余数起,一直到最前面的一个余数。

3、实现

首先我们工具类中会提供两个功能,一个是十进制转六十四进制,一个是六十四进制转十进制,我们先来看十进制转六十四进制:
用上面的除64取余,然后直到商为止,那么伪代码可以是如下所示:

  1. StringBuilder buf = new StringBuilder();
  2. while (number != 0) {
  3. //获取余数
  4. buf.append(除64获取余数);
  5. //剩下的值
  6. number64
  7. }
  8. //因为是从最后开始读的,所以这里要反转
  9. return buf.reverse().toString();

如果是六十四进制转十进制,那么就用上面的进制转换原理。我们只需要对六十四进制的字符串从最右边开始一个个处理即可。比如64进制的字符串rtyu0u那么值应该是

  1. r*64^5+t*64^4+y*64^3+u*64^2+0*64^1+u*64^0

那么关键的一部是我们需要获取到r,t,y,u,0,u对应在64进制表对应的值是多少,比如下面是64进制表:

  1. 0 1 2 3 4 5 6 7 8 9 a(10) b(11) c(12) d(13) e(14) f(15) g(16) h(17) i(18) j(19) k(20) l(21) m(22) n(23) o(24) p(25) q(26) r(27) s(28) t(29) u(30) v(31) w(32) x(33) y(34) z(35) A(36) B(37) C(38) D(39) E(40) F(41) G(42) H(43) I(44) J(45) K(46) L(47) M(48) N(49) O(50) P(51) Q(52) R(53) S(54) T(55) U(56) V(57) W(58) X(59) Y(60) Z(61) +(62) /(63)

很明显r是27,t是29,y是34,u是30,那么rtyu0u转换成十进制的值是:29486604318。也就是我们只需要确定u这些在定义表中对应的位置就是他们的值啦。方法如下,因为参照ASCII码表可以知道,上面的字母和数字都在ASCII码表中对应有数字,可以查看:Java的char自动转int的转换原理,也就是比如我们的字母u,就在ASCII表中对应的数字是:117,它在64进制对应的是30,因此,我们只需要构造类似a[117]=30的数组即可。

源码如下:

  1. public class ConversionUtil {
  2. //这里最后一位用-比较好,因为/比较特殊
  3. private static final String baseDigits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-";
  4. private static final int BASE = baseDigits.length();
  5. //通过余数获取对应的64进制表示
  6. private static final char[] digitsChar = baseDigits.toCharArray();
  7. //这里预留了足够的空位122位
  8. private static final int FAST_SIZE = 'z';
  9. //这个是为了存放字母对应的值,比如-对应63,但是-是45,也就是 digitsIndex[45]=63
  10. //[digitsChar[-]会自动转变成45,这样子十六进制转十进制,就可以获取到前面的数字了。
  11. private static final int[] digitsIndex = new int[FAST_SIZE + 1];
  12. static {
  13. for (int i = 0; i < FAST_SIZE; i++) {
  14. digitsIndex[i] = -1;
  15. }
  16. //构造:a[117]=30这样的数组
  17. for (int i = 0; i < BASE; i++) {
  18. digitsIndex[digitsChar[i]] = i;
  19. }
  20. }
  21. //64进制转十进制
  22. public static long decode(String s) {
  23. long result = 0L;
  24. long multiplier = 1;
  25. for (int pos = s.length() - 1; pos >= 0; pos--) {
  26. int index = getIndex(s, pos);
  27. result += index * multiplier;
  28. multiplier *= BASE;
  29. }
  30. return result;
  31. }
  32. //十进制转64进制
  33. public static String encode(long number) {
  34. if (number < 0)
  35. System.out.println("Number(Base64) must be positive: " + number);
  36. if (number == 0)
  37. return "0";
  38. StringBuilder buf = new StringBuilder();
  39. while (number != 0) {
  40. //获取余数
  41. buf.append(digitsChar[(int) (number % BASE)]);
  42. //剩下的值
  43. number /= BASE;
  44. }
  45. //反转
  46. return buf.reverse().toString();
  47. }
  48. //获取对应的的64进制的值
  49. private static int getIndex(String s, int pos) {
  50. char c = s.charAt(pos);
  51. if (c > FAST_SIZE) {
  52. System.out.println("Unknow character for Base64: " + s);
  53. }
  54. int index = digitsIndex[c];
  55. if (index == -1) {
  56. System.out.println("Unknow character for Base64: " + s);
  57. }
  58. return index;
  59. }
  60. }

如果是生成短连接,建议除开+,-。

 1380

啊!这个可能是世界上最丑的留言输入框功能~


当然,也是最丑的留言列表

有疑问发邮件到 : suibibk@qq.com 侵权立删
Copyright : 个人随笔   备案号 : 粤ICP备18099399号-2