编码原理(10进制转62进制):
1.将输入数据视为一个大整数
2.不断除以62,将余数映射为对应的BASE62字符
3.将余数逆序排列得到编码结果
解码原理(62进制转10进制):
1.将每个BASE62字符转换回对应的数值
2.从右到左,每个位置的数值乘以62的相应次方
3.累加所有结果得到原始数据
java
package com.ustc.util;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
/**
* Base62 编码解码工具类
* <p>
* 编码原理(10进制转62进制):
* 1.将输入数据视为一个大整数
* 2.不断除以62,将余数映射为对应的BASE62字符
* 3.将余数逆序排列得到编码结果
* <p>
* 解码原理(62进制转10进制):
* 1.将每个BASE62字符转换回对应的数值
* 2.从右到左,每个位置的数值乘以62的相应次方
* 3.累加所有结果得到原始数据
* @Author:
* @Date: 2025-10-25 16:16
*/
public class Base62 {
// 编码后的结果与这个字符集顺序有关
private static final String BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
// 基数62
private static final BigInteger BASE = BigInteger.valueOf(62);
/**
* 将字节数组编码为BASE62字符串
* @param input 输入字节数组
* @return BASE62编码字符串
*/
public static String encode(byte[] input) {
if (input == null || input.length == 0) {
return "";
}
// 将字节数组视为一个大整数
BigInteger number = new BigInteger(1, input);
StringBuilder result = new StringBuilder();
// 实际上就是将十进制数转换为62进制过程
// 不断除以62,取余数,直到商为0,再将余数映射到62个字符上,最后倒序排列
while (number.compareTo(BigInteger.ZERO) > 0) {
// 同时进行除法和取余运算,返回一个包含商和余数的数组
BigInteger[] divmod = number.divideAndRemainder(BASE);
number = divmod[0]; // 商
int remainder = divmod[1].intValue(); // 余数
result.append(BASE62.charAt(remainder));
}
// 处理前导零(BigInteger会忽略前导零,需要特殊处理)
for (byte b : input) {
if (b == 0) {
result.append(BASE62.charAt(0));
} else {
break;
}
}
// 反转字符串,因为我们在循环中是先得到低位字符
return result.reverse().toString();
}
/**
* 将BASE62字符串解码为字节数组
* @param input BASE62编码字符串
* @return 原始字节数组
*/
public static byte[] decode(String input) {
if (input == null || input.length() == 0) {
return new byte[0];
}
// 实际上就是将62进制数转换为十进制过程
// 从右往左:余数*(62^0) + 余数*(62^1) + 余数*(62^2) + ...
BigInteger number = BigInteger.ZERO;
for (char c : input.toCharArray()) {
int digit = BASE62.indexOf(c); // 余数
// number = number * 62 + digit
number = number.multiply(BASE).add(BigInteger.valueOf(digit));
}
// 假如是4位的一个62进制数,上面这个for循环计算过程:
// number1 = number * 62 + digit1
// number2 = number1 * 62 + digit2
// number3 = number2 * 62 + digit3
// number4 = number3 * 62 + digit4
// 对循环过程转换一下公式:
// number1 = number * 62 + digit1 = number*(62^1) + digit1*(62^0)
// number2 = number1 * 62 + digit2 = number*(62^2) + digit1*(62^1) + digit2*(62^0)
// number3 = number2 * 62 + digit3 = number*(62^3) + digit1*(62^2) + digit2*(62^1) + digit3*(62^0)
// number4 = number3 * 62 + digit4 = number*(62^4) + digit1*(62^3) + digit2*(62^2) + digit3*(62^1) + digit4*(62^0)
// 因为初始number=0带入上面公式,可以看出刚好就是62进制转10进制的公式,最后number就是转换后的10进制数(大整数)
// 将大整数转换为字节数组
byte[] bytes = number.toByteArray();
// 处理前导零,若最高位为0x00(因BigInteger.toByteArray()会补位),则去除
if (bytes[0] == 0) {
// 去掉原数组的第一个字节(索引为 0 的元素),返回一个长度减 1 的新数组
bytes = Arrays.copyOfRange(bytes, 1, bytes.length);
}
// 回顾encode编码的过程,当从首位开始,字节值连续为0,使用第一位字符集填充的这些0
// 所以这里逆向这个过程,当从首位开始,字符连续为第一位字符集的字符,使用0填充回去。
int leadingZeroes = 0; //首位开始连续为0的个数(前导零的个数)
for (char c : input.toCharArray()) {
if (c == BASE62.charAt(0)) {
leadingZeroes++;
} else {
break;
}
}
// 拼接前导零字节和实际数据
byte[] result = new byte[leadingZeroes + bytes.length];
// 前半部分填充0x00
System.arraycopy(bytes, 0, result, leadingZeroes, bytes.length);
return result;
}
public static void main(String[] args) {
String input = "你好";
String encoded = Base62.encode(input.getBytes(StandardCharsets.UTF_8));
String decoded = new String(Base62.decode(encoded), StandardCharsets.UTF_8);
System.out.println("原始: " + input);
System.out.println("加密: " + encoded);
System.out.println("解密: " + decoded);
}
}
参考: