跳至正文
LNN的博客!

奇怪的AV号-BV号转换程序增加了!

众所周知,哔哩哔哩已经把旧版视频番号AV号隐藏,只显示新版番号BV号,而这两种番号可以通过一个算法相互转换。

我用两种深奥编程语言,即娱乐性大于实用性的编程语言实现了番号转换,话不多说,直接上源码

文言 wenyan-lang

以下代码写于2020年3月

吾嘗觀位經之書方悟異或之義
吾嘗觀列經之書方悟索一之義
吾嘗觀算經之書方悟取底之義

吾有名之曰字母表」。
字母表『f』『Z』『o』『d』
『R』『9』『X』『Q』『D』『S』
『U』『m』『2』『1』『y』『C』
『k』『r』『6』『z』『B』『q』
『i』『v』『e』『Y』『a』『h』
『8』『b』『t』『4』『x』『s』
『W』『p』『H』『n』『J』『E』
『7』『j』『L』『5』『V』『G』
『3』『g』『u』『M』『T』『K』
『N』『P』『A』『w』『c』『F』

吾有名之曰亂序表」。
亂序表一十

吾有一億七千七百四十五萬一千八百一十二名之曰異或數」。

吾有名之曰加數」。
加數五十五一十七一十七
一十三一十三四十三十一一十三

今有名之曰甲號轉乙號」。欲行是術必先得甲號」。乃行是術曰
 異或甲號異或數」。名之曰」。
 吾有名之曰」。
 吾有名之曰乙號」。
 吾有名之曰」。
 恆為是大於乃止也
  加數」。」。昔之是矣
  」。五十八所餘幾何
  」。五十八以施取底」。昔之是矣
 」。昔之是矣云云
 亂序表中之
  」。字母表乙號」。昔之乙號是矣
 云云
 乃得乙號」。
是謂甲號轉乙號之術也

今有名之曰乙號轉甲號」。欲行是術必先得乙號」。乃行是術曰
 吾有名之曰」。
 吾有名之曰」。」。
 恆為是大於乃止也
  字母表」。乙號」。以施索一」。名之曰」。
  亂序表」。名之曰」。
  昔之是矣
 」。昔之是矣云云
 昔之是矣恆為是小於乃止也
  」。名之曰」。
  加數」。名之曰」。
  五十八」。」。昔之是矣
 」。昔之是矣云云
 異或」。異或數」。乃得矣
是謂乙號轉甲號之術也

甲號轉乙號一十七萬零一書之
乙號轉甲號『17x411w7KC』書之

dongbei - 东北方言编程语言

以下代码写于2020年8月

异或(老张,老王)咋整:
    滚犊子吧整eval(老张、“^”、老王)。
整完了。

老几(张家庄,老张)咋整:
    几从一到(张家庄有几个坑)磨叽:
        寻思:老张跟张家庄的老几一样一样的?
        要行咧就滚犊子吧几。
    磨叽完了。
    滚犊子吧零。
整完了。

字母表装「“f”,“Z”,“o”,“d”,“R”,“9”,“X”,“Q”,
“D”,“S”,“U”,“m”,“2”,“1”,“y”,“C”,“k”,“r”,
“6”,“z”,“B”,“q”,“i”,“v”,“e”,“Y”,“a”,“h”,
“8”,“b”,“t”,“4”,“x”,“s”,“W”,“p”,“H”,“n”,
“J”,“E”,“7”,“j”,“L”,“5”,“V”,“G”,“3”,“g”,
“u”,“M”,“T”,“K”,“N”,“P”,“A”,“w”,“c”,“F”」。
乱序表装「7,3,5,9,6,10,4,8,2,1」。
异或数装177451812。
【加数】装「6,55,3,17,17,13,13,40,31,13」。

AV转BV(AV号)咋整:
    老王装整异或(AV号,异或数)。
    张家庄都是活雷锋。
    BV号装“”。
    几从一到十磨叽:
        老王装(老王加【加数】的老几)。
        张家庄来了个(老王刨掉一堆堆58)。
        老王装(老王齐整整地除以58)。
    磨叽完了。
    几在乱序表磨叽:
        BV号装BV号、字母表的老(张家庄的老几加一)。
    磨叽完了。
    滚犊子吧BV号!
整完了。

BV转AV(BV号)咋整:
    张家庄都是活雷锋。
    老王装零。
    几从一到十磨叽:
        张家庄来了个零。
    磨叽完了。
    几从一到十磨叽:
        张家庄的老(乱序表的老几)装整老几(字母表,BV号的老几)减一。
    磨叽完了。
    几从一到十磨叽:
        老王装老王乘58加(张家庄的老(11减几))减(【加数】的老(11减几))。
    磨叽完了。
    滚犊子吧整异或(老王,异或数)!
整完了。

唠唠:整AV转BV(170001)。
唠唠:整BV转AV(“17x411w7KC”)。

(附赠完美PHP版本)

以下代码写于2020年7月

<?php
/**
 * AV号、BV号转换
 * 
 * @author DGCK81LNN
 */

$avbv_alphabet = 'fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF';
$avbv_table = array();
for ($i = 0; $i < strlen($avbv_alphabet); $i++) {
    $avbv_table[] = substr($avbv_alphabet, $i, 1);
}
$avbv_bvreg = "/^[$avbv_alphabet]{10}\$/u";
$avbv_s = [6, 2, 4, 8, 5, 9, 3, 7, 1, 0];
$avbv_xor = 177451812;
$avbv_add = [6, 55, 3, 17, 17, 13, 13, 40, 31, 13];

/**
 * AV号转BV号
 * 
 * @param int|string $av
 * @return string 带“BV”前缀的BV号
 * 
 * @throws InvalidArgumentException 传入的参数不是整数或字符串
 * @throws DomainException 传入的整数不是正整数
 * @throws UnexpectedValueException 传入的字符串不是"AV"后接一个十进制正整数的形式
 */
function av2bv($av)
{
    global $avbv_table, $avbv_s, $avbv_xor, $avbv_add;
    $dump = var_export($av, true);
    $num = NAN;
    if (is_integer($av))
        if ($num <= 0)
            throw new DomainException("av2bv($dump): AV号必须大于0");
        else
            $num = $av;
    else if (is_string($av))
        if (preg_match("/^AV[1-9][0-9]*$/i", $av))
            $num = (int)substr($av, 2);
        else
            throw new UnexpectedValueException("av2bv($dump): AV号格式有误");
    else
        throw new InvalidArgumentException("av2bv($dump): 参数必须是整数或字符串");

    $num ^= $avbv_xor;
    $num58 = array();
    $result = 'BV';
    for ($i = 0; $i < 10; $i++) {
        $num += $avbv_add[$i];
        $num58[] = $num % 58;
        $num = floor($num / 58);
    }
    foreach ($avbv_s as $digitIndex)
        $result .= $avbv_table[$num58[$digitIndex]];
    return $result;
}

/**
 * BV号转AV号
 * (“BV”后的“1”不能省略)
 * 
 * @param string $bv
 * @param bool $returnNumber 是否要返回一个整数。默认返回带“AV”前缀的字符串。
 * @return int|string 带“AV”前缀的AV号,或整数形式的AV号
 * 
 * @throws InvalidArgumentException 第一个参数不是字符串
 * @throws UnexpectedValueException 传入的BV号不符合10位base58或“BV”后接10位base58的格式
 * @throws RangeException 进行按位异或运算后得到负数
 */
function bv2av($bv, $returnNumber = false)
{
    global $avbv_table, $avbv_bvreg, $avbv_s, $avbv_xor, $avbv_add;
    $dump = var_export($bv, true);
    $str = '';
    $err = false;
    if (!is_string($bv))
        throw new InvalidArgumentException("bv2av($dump): 第一个参数必须是字符串");

    if (strlen($bv) === 10)
        $str = $bv;
    else if (strlen($bv) === 12 && stripos($bv, 'BV') === 0)
        $str = substr($bv, 2);
    else
        $err=true;
    if($err || !preg_match($avbv_bvreg, $str))
        throw new UnexpectedValueException("bv2av($dump): BV号格式有误");

    $num58 = array();
    $num = 0;
    for ($i = 0; $i < 10; $i++) {
        $char = $str[$i];
        $num58[$avbv_s[$i]] = array_search($char, $avbv_table);
    }
    for ($i = 9; $i >= 0; $i--) {
        $num *= 58;
        $num += $num58[$i] - $avbv_add[$i];
    }
    $num ^= $avbv_xor;
    if ($num <= 0)
        throw new RangeException("bv2av($dump): AV号溢出 ($num)");

    return $returnNumber ? $num : "AV$num";
}

/**
 * 将任意格式的视频番号转换为AV号数字
 * (“BV”后的“1”不能省略)
 * 
 * @param int|string $input
 * @return int 整数形式的AV号
 * 
 * @throws InvalidArgumentException 传入的参数不是整数或字符串
 * @throws DomainException 传入的整数不是正整数
 * @throws UnexpectedValueException 无法识别传入的字符串番号
 * @throws RangeException 进行按位异或运算后得到负数
 */
function getAID($input)
{
    global $avbv_bvreg;
    $dump = var_export($input, true);
    if (is_integer($input))
        if ($input <= 0)
            throw new DomainException("getAID($dump): AV号必须大于0");
        else
            return $input;
    else if (is_string($input)) {
        if (preg_match("/^AV[1-9][0-9]*$/i", $input))
            return (int)substr($input, 2);
        else if (preg_match($avbv_bvreg, substr($input, 2)))
            return bv2av($input);
        else if (stripos($input, 'BV') === 0 && preg_match($avbv_bvreg, substr($input, 2)))
            return bv2av($input);
        else
            throw new UnexpectedValueException("getAID($dump): 字符串参数格式有误");
    }
    else
        throw new InvalidArgumentException("getAID($dump): 参数必须是整数或字符串");

}

/**
 * 将任意格式的视频番号转换为BV号字符串
 * (“BV”后的“1”不能省略)
 * 
 * @param int|string $input
 * @return string
 * 
 * @throws InvalidArgumentException 传入的参数不是整数或字符串
 * @throws DomainException 传入的整数不是正整数
 * @throws UnexpectedValueException 无法识别传入的字符串番号
 */
function getBVID($input)
{
    global $avbv_bvreg;
    $dump = var_export($input, true);
    if (is_integer($input))
        if ($input <= 0)
            throw new DomainException("getBVID($dump): AV号必须大于0");
        else
            return av2bv($input);
    else if (is_string($input)) {
        if (preg_match("/^AV[1-9][0-9]*$/i", $input))
            return av2bv($input);
        else if (preg_match($avbv_bvreg, substr($input, 2)))
            return "BV$input";
        else if (stripos($input, 'BV') === 0 && preg_match($avbv_bvreg, substr($input, 2)))
            return $input;
        else
            throw new UnexpectedValueException("getBVID($dump): 字符串参数格式有误");
    }
    else
        throw new InvalidArgumentException("getBVID($dump): 参数必须是整数或字符串");
}
?>

(附赠略简陋JS版本)

以下代码写于2020年3月

const table = [...'fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF'];
const s = [6, 2, 4, 8, 5, 9, 3, 7, 1, 0];
const xor = 177451812;
const add = [6, 55, 3, 17, 17, 13, 13, 40, 31, 13];

const av2bv = (av) => {
    let num = NaN;
    if (typeof av === 'number') {
        num = Math.floor(av);
    } else if (typeof av === 'string') {
        if (av.toUpperCase().startsWith("AV"))
            num = Math.floor(av.substr(2));
    } else {
        let e = new Error();
        e.name = "TypeError";
        e.message =  '传入的AV号必须是字符串或数字';
        throw e;
    };
    if (isNaN(num)){
        let e = new Error();
        e.name = "SyntaxError";
        e.message =  'AV号必须是数字';
        throw e;
    }
    else if (num <= 0) {
        let e = new Error();
        e.name = "RangeError";
        e.message =  'AV号必须大于0';
        throw e;
    };

    num ^= xor;
    let num58 = [], result = "BV";
    for (let i=0; i<10; i++) {
        num += add[i];
        num58.push(num%58);
        num = Math.floor(num/58);
    }
    s.forEach(digitIndex => result += table[num58[digitIndex]]);
    return result;
};

const bv2av = bv => {
    let str = '';
    if (typeof bv !== "string") {
        let e = new Error();
        e.name = "TypeError";
        e.message =  '传入的BV号必须是字符串';
        throw e;
    };
    if (bv.length === 10) {
        str = bv;
    } else if (bv.length === 12 && bv.toUpperCase().startsWith("BV")) {
        str = bv.substr(2);
    } else {
        let e = new Error();
        e.name = "SyntaxError";
        e.message =  'BV号必须是10位字母数字编码';
        throw e;
    };
    if (!str.match(/[fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF]{10}/gu)) {
        let e = new Error();
        e.name = "SyntaxError";
        e.message =  'BV号含有非法字符';
        throw e;
    };

    let num58 = [], num=0;
    [...str].forEach((char, i) => {
        num58[s[i]] = table.indexOf(char);
    });
    for (let i=9; i>=0; i--){
        num *= 58;
        num += num58[i] - add[i];
    }
    num ^= xor;
    return "AV" + num;
};

评论区

加载基于 GitHub issues 的 utteranc.es 评论区组件……