package com.learn.bilibili.idconv;
public class IDConvUtil {
/**
* 假定:
* avid为数字(例如数据库主键id),bvid为 可与avid相互转换的 数字字母组成的12位的id.
* bvid固定格式:BV1__4_1_7__
* 一、通过将avid数字,填充到bvid空位上。实现 avid -> bvid 的编码。
* 二、通过将bvid对应位之上的字符,按相反顺序,还原成avid数字。实现 bvid -> avid 的解码。
*/
//table:用来 对应 58进制的字符(58进制每个数字,对应一个字符)
static String table = "fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF";
//定义bvid(BV1__4_1_7__) 空余位置,(avid转换为bvid时)被填充的顺序
static int[] seqArray = new int[]{11, 10, 3, 8, 4, 6};
//默认的基础BVid模板.
//char[] defaultBVId = new char[]{'B','V','1',' ',' ','4',' ','1',' ','7',' ',' '};
// xOr与avid进行异或运算,xAdd与avid进行加或减运算。
// 加密时,异或xOr、加xAdd。 解密时,减xAdd、再异或xOr (能还原元数据,相当于啥也没干)
static long xOr = 177451812L;
static long xAdd = 8728348608L;
public static void main(String[] args) {
//测试 avid -> bvid 的编码
//数字av 编号id
long av1 = 884740535L;
String bv1 = avEncode(av1);
System.out.printf("avid:%d <=> bvid: %s \n", av1, bv1);
//测试 bvid -> avid 的解码
String bv2 = "BV1rK4y187eg";
long av2= bvDecode(bv2);
System.out.printf("bvid:%s <==> avid:%d \n",bv2,av2);
//测试输出:
//avid:884740535 <=> bvid: BV1rK4y187eg
//bvid:BV1rK4y187eg <==> avid:884740535
}
/**
* 将数字的avid 编码为 由数字、字母组成的bvid 字符id.
*
* @param av1
* @return
*/
private static String avEncode(long av1) {
//将avid 进行异或、加上特定数值(解码时会还原 此部分)
long newAvId = (av1 ^ xOr) + xAdd;
//1.将 newAvId 转换为 6位长度的 58进制数(58进制表示规则由table决定):
// fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF
//2.并将这6位数按照 seqArray {11,10,3,8,4,6} 设定下标的顺序(将6位数翻转:11对应个位,6对应最高位),
// 填入 初始bvid模板:BV1__4_1_7__
//例:转换完成的 6位58进制为:yK8reg,g是个位,
// 所以yK8reg分别对应bvid的下标 y(6)K(4)8(8)r(3)e(10)g(11)
// 则填充后 bvid为: BV1rK4y187eg
char[] defaultBVId = new char[]{'B', 'V', '1', ' ', ' ', '4', ' ', '1', ' ', '7', ' ', ' '};
for (int i = 0; i < seqArray.length; i++) {
//进制转换 i=0时得到的是转换为58进制时,个位的数字。(0~57)
//int indexOfTable = (int) (newAvId / ((long) Math.pow(58, i)) % 58);
//将58进制的该位数字,转化为字母(按我们预设的规则 table)
//char c = table.charAt(indexOfTable);
//找到该字符 在bvid中的位置
//int indexOfDefaultBVId = seqArray[i];
//将字符填充到 bvid模板中。
//defaultBVId[indexOfDefaultBVId] = c ;
//上面可以合并为:
defaultBVId[seqArray[i]] = table.charAt((int) (newAvId / ((long) Math.pow(58, i)) % 58));
}
return new String(defaultBVId);
}
/**
* 将编码后的数字、字母组成的bvid,解码为数字的avid.
*
* @param bv
* @return
*/
private static long bvDecode(String bv) {
long newAvId = 0L;
for (int i = 0; i < seqArray.length; i++) {
//从填充位,得到58进制字符
//char c = bv.charAt(seqArray[i]);
//将字符转换会58进制数字
//int indexOfTable = table.indexOf(c);
//将数字 根据其位置 i 转换成十进制数字
//long num = indexOfTable* (long)Math.pow(58,i);
//进制转换公式
//newAvId +=num;
//上面操作合并为:
newAvId += table.indexOf(bv.charAt(seqArray[i])) * (long)Math.pow(58,i);
}
// 还原编码时的操作
long avid = (newAvId - xAdd)^xOr;
return avid;
}
}
[java] B站 avid bvid 转换算法
于 2022-04-15 17:11:56 首次发布