JS 按自定义格式 拼接二进制串 解析二进制串_世界观察

作者: 来源: 腾讯云 2023-04-24 06:45:51

 

本文解答:JS如何按自定义格式拼接二进制串?如何解析二进制串?

什么是二进制串?

当你要存一些数据时,可以用自定义格式存下来,这样最节约空间。

例如,你想存这些数据:


(资料图片)

ID(范围0-16)是否VIP(范围0-1)星座(范围0-11)年龄(范围0-127)

那么你可以规定这种自定义格式的二进制串:dddddddc cccbaaaa其中d c b a都是代表0或1,我们用最后4位(aaaa)表示“ID”,用b表示“是否VIP”,用ccc表示“星座”,用dddd表示年龄。

本来你可能会用uint32的数组来存这些,占4*32=128位,但是现在,我们只用了16位,2个uint8就存下了。非常节约存储空间。这就是一种自定义格式的二进制串。

注意:当今存储确实不贵,但是如果你希望把信息存放到URL中,那么你的空间越小,URL就越短。这时候价值就非常大了。例如我之前开发象棋小游戏,把棋局信息(包括当前棋盘状态、所有回合操作记录)都存到了URL中,就能非常方便的保存、分享游戏对局,方便大家复盘。详见文章《保存象棋棋盘信息,需要多少比特?我只用139-167位二进制》

在JS中,对应的数据类型是Uint8Array。

拼接自定义格式二进制串

function concatBits(current: number, offset: number, bits: number, bitsLength: number) {  let newCurrent = current;  let newOffset = offset;  const newUint8: number[] = [];  if (offset + bitsLength < 8) {    newCurrent |= bits << (8 - bitsLength - offset);    newOffset += bitsLength;  } else if (offset + bitsLength === 8) {    newUint8.push(current | bits);    newCurrent = 0;    newOffset = 0;  } else {    newCurrent |= bits >> (offset - 8 + bitsLength);    newUint8.push(newCurrent);    newCurrent = (bits << (16 - offset - bitsLength)) & 0xff;    newOffset = offset - 8 + bitsLength;  }  return [newCurrent, newOffset, newUint8];}

当然这还是有个限制:bitsLength必须小于等于8。如果超过8,可能一个bits要覆盖3个uint8,这种情况没考虑在内。

如果你需要拓展,欢迎继续完善它!

解析自定义格式二进制串

function readBits(array: Uint8Array, bitsOffset: number, bitsLength: number) {  const offset = bitsOffset % 8;  const index = Math.floor(bitsOffset / 8);  if ((offset + bitsLength > 8 && index + 1 >= array.length) || offset + bitsLength <= 8 && index >= array.length) {    throw new Error("readBitsError");  }  let number = offset + bitsLength <= 8 ? array[index] : (array[index] << 8) | array[index + 1];  const length = offset + bitsLength <= 8 ? 8 : 16;  number >>= (length - bitsLength - offset);  number &= ([0, 1, 3, 7, 15, 31, 63][bitsLength]);  return [number, bitsOffset + bitsLength];}

decode难点

相比encode,decode其实是更难的事情。

因为encode时,你只需要无脑往一个字节串后面补充就好。而decode需要你非常清楚,每一位的作用,并理解他们的含义。你需要有高超的位运算技巧,才能轻易完成。

如何知道一共有多少项目

设计数据结构时,我们没有把项目数作为一个变量,所以数组长度是未知的。

也就是说,我们必须不断循环,直到这个字节串没有内容了,我们就终止。

如何读取制定长度bit位的内容

我们封装一个函数readBits,用于读取某个字节串,从第x位开始、长度为n的内容。

因此,需要3个参数:

字节串array位偏移量bitsOffset要读取的长度bitsLength

返回值主要是对应的内容(可以用一个uint8来表示),此外,读取后还需要更新一下调用者的位偏移量bitsOffset,方便持续调用,所以我们顺便把新的位偏移量bitsOffset返回,作为返回值第二项。

解释

在本文场景下,要读取的长度bitsLength不超过8,所以我们要关注的数据量,只会来自1个uint8或者某连续2个uint8。

计算index就是为了判断第一个关键的uint8的位置。

计算offset,知道应该从index的第几位开始算数。

然后通过比较offset + bitsLength8的大小,就知道我们需要关注1个uint8即可、还是需要关注连续2个uint8。

我们把需要关注的uint8赋值给number,用length表示我们关注8位还是16位。

例如number二进制是10110000,我们需要取从2开始的长度为2的内容(即11)。该怎么做呢?

只需要把它右移4位(用于删除不需要的后缀),再跟二进制11做个与操作(用于删除不需要的前缀),即可。

因此代码会这样写:number >>= (length - bitsLength - offset);number &= ([0, 1, 3, 7, 15, 31, 63][bitsLength]);

其中0 1 3 7 15 31 63,对应二进制分别是0 1 11 111 1111 11111 111111。都是为了删除前缀。

这里因为我需要的bitsLength有限,所以我用这种方式偷懒了。如果你要做的更通用,可能要这样写:2 ** bitsLength - 1,目的是获取位长度为bitsLength的全是1的数字,用于删除number不需要的前缀。

readBits开发完毕,以后可以这样调用:

let current;let bitsOffset = 0;[current, bitsOffset] = readBits(array, bitsOffset, 4);

这会读取字节串array的从第0位开始、长度为4个bit位的内容,赋值给current变量。

写在最后

我是HullQin,公众号线下聚会游戏的作者(欢迎关注我,交个朋友)。转发本文前需获得作者HullQin授权。我独立开发了《联机桌游合集》,是个网页,可以很方便的跟朋友联机玩UNO、飞行棋、斗地主、五子棋、一夜狼、狼人杀、象棋、德国心脏病、达芬奇密码等游戏,不收费无广告。还开发了《Dice Crush》参加Game Jam 2022。喜欢可以关注我噢~我有空了会分享做游戏的相关技术,会在这个专栏里分享:《教你做小游戏》。

 

相关文章
最近更新
  • JS 按自定义格式 拼接二进制串 解析二进制串_世界观察

    JS 按自定义格式 拼接二进制串 解析二进制串_世界观察

    2023-04-24

  • 为什么猫咪会怕黄瓜_为什么猫会怕黄瓜 微资讯

    为什么猫咪会怕黄瓜_为什么猫会怕黄瓜 微资讯

    2023-04-24

  • 毕竟不是顶级球星,快船后场大将已经承担了超出个人能力的任务?|全球快报

    毕竟不是顶级球星,快船后场大将已经承担了超出个人能力的任务?|全球快报

    2023-04-24

  • 世界快消息!勇三疯再现!勇士第三节打出37-23净胜国王14分

    世界快消息!勇三疯再现!勇士第三节打出37-23净胜国王14分

    2023-04-24

  • 利文斯顿谈追梦替补:这体现了他的篮球智商和谦逊-全球看点

    利文斯顿谈追梦替补:这体现了他的篮球智商和谦逊-全球看点

    2023-04-24

  • 主要表现怎么写 团代表_主要表现怎么写

    主要表现怎么写 团代表_主要表现怎么写

    2023-04-24

  • 灰指甲的初期症状怎么治疗最好_灰指甲的初期症状怎么治疗

    灰指甲的初期症状怎么治疗最好_灰指甲的初期症状怎么治疗

    2023-04-24

  • 盗贼单刷玛拉顿自然抗装备_盗贼单刷玛拉顿

    盗贼单刷玛拉顿自然抗装备_盗贼单刷玛拉顿

    2023-04-24

  • 灰色牛仔裤掉色怎么办_牛仔裤掉色怎么办

    灰色牛仔裤掉色怎么办_牛仔裤掉色怎么办

    2023-04-24

  • 防范利差损风险,人身险产品预定利率下调至3%

    防范利差损风险,人身险产品预定利率下调至3%

    2023-04-24

  • 当日快讯:一博科技:增收不增利,一季度归母净利同比下滑14.95%|新消息

    当日快讯:一博科技:增收不增利,一季度归母净利同比下滑14.95%|新消息

    2023-04-24

  • 当日快讯:华伍股份:风电产品毛利率下降等,2022年年归母净利同比下滑38.9%

    当日快讯:华伍股份:风电产品毛利率下降等,2022年年归母净利同比下滑38.9%

    2023-04-24

  • 世界微头条丨当日快讯:宏德股份:整体材料成本增长等,2022年年归母净利润同比下滑22.23%,拟10派2.5元

    世界微头条丨当日快讯:宏德股份:整体材料成本增长等,2022年年归母净利润同比下滑22.23%,拟10派2.5元

    2023-04-24

  • 女孩子怎么混社会 女孩怎么混社会-播报

    女孩子怎么混社会 女孩怎么混社会-播报

    2023-04-24

  • 风筝拼音怎么拼读(风筝拼音)_世界微头条

    风筝拼音怎么拼读(风筝拼音)_世界微头条

    2023-04-24

  • 手机qq看点怎么私信作者(手机qq看点怎么关闭) 每日头条

    手机qq看点怎么私信作者(手机qq看点怎么关闭) 每日头条

    2023-04-24

  • 小米手机屏幕截图的快捷键是什么(小米手机截屏快捷键是哪个)

    小米手机屏幕截图的快捷键是什么(小米手机截屏快捷键是哪个)

    2023-04-24

  • 怎么把音频转换成wav格式(怎么把音频转换成文字)

    怎么把音频转换成wav格式(怎么把音频转换成文字)

    2023-04-24

  • 世界快播:女犯文学冤狱_女犯文学警花老婆

    世界快播:女犯文学冤狱_女犯文学警花老婆

    2023-04-24

  • 春蚕秋收残冬是什么三部曲_春蚕-天天时快讯

    春蚕秋收残冬是什么三部曲_春蚕-天天时快讯

    2023-04-24

  • 环球通讯!女孩舞蹈技巧有哪些_舞蹈技巧有哪些

    环球通讯!女孩舞蹈技巧有哪些_舞蹈技巧有哪些

    2023-04-24

  • 中之人招募

    中之人招募

    2023-04-24

  • 狼王光临银河战舰!克罗斯晒与托蒂合影,并配文:传奇?

    狼王光临银河战舰!克罗斯晒与托蒂合影,并配文:传奇?

    2023-04-24

  • Woj:联盟审查了狄龙对詹姆斯的二级恶犯 不会有追加禁赛处罚

    Woj:联盟审查了狄龙对詹姆斯的二级恶犯 不会有追加禁赛处罚

    2023-04-24

  • 德容:重返赛场让我感到开心 击败马竞这样的对手给了球队信心_世界头条

    德容:重返赛场让我感到开心 击败马竞这样的对手给了球队信心_世界头条

    2023-04-24

  • “上海手记”影展开幕,记录在手机里的城市模样

    “上海手记”影展开幕,记录在手机里的城市模样

    2023-04-24

  • 当前消息!哈尔滨师范大学贴吧诚信记录_哈尔滨师范大学贴吧

    当前消息!哈尔滨师范大学贴吧诚信记录_哈尔滨师范大学贴吧

    2023-04-24

  • 药物制剂专业就业前景薪酬_药物制剂专业就业前景 热头条

    药物制剂专业就业前景薪酬_药物制剂专业就业前景 热头条

    2023-04-24

  • 胡萝卜的热量和含糖量是多少_胡萝卜的热量

    胡萝卜的热量和含糖量是多少_胡萝卜的热量

    2023-04-24

  • 白化病有什么危害吗会传染吗_白化病会传染吗 怎么治疗

    白化病有什么危害吗会传染吗_白化病会传染吗 怎么治疗

    2023-04-24