字符串怎么承载 int32 信息?

2021-09-16 16:19:12 +08:00
 JustLookBy

需求:js 传输的 json 字符串里面有坐标数组,坐标数值都小于 4,096 。 尽可能压缩传输体积。

目前想法是 把 x,y 坐标直接 (x<<16)|y 聚集成一个 int32 值,刚好 4 个字节对应 utf8 4 个字节,然而有很多字符都没对应的,所以无法一一转化.

用的是 websocket 传输,虽然支持 arrayBuffer 类型,但是我的数据都是字符串格式的,还有其他信息要一起。

大佬们有什么方案吗?把坐标压缩到字符串里面节省空间

2858 次点击
所在节点    程序员
26 条回复
lasuar
2021-09-16 16:23:58 +08:00
我有个问题,你这个 (x<<16)|y 操作可逆吗? 另外,你要节省就直接传 binary,别整 json 。
JustLookBy
2021-09-16 16:32:40 +08:00
@lasuar 可逆啊,因为坐标值都小于 4,096

n = (x<<16)|y ; x=n>>16;y=n & (0xff-1)

传 binary 是最后方案了
zjsxwc
2021-09-16 16:34:08 +08:00
压缩 json 用这个库不行吗?
https://github.com/rgcl/jsonpack
chenluo0429
2021-09-16 16:35:23 +08:00
比如对于坐标 2423,2342,使用坐标字符串是{"point":"2423,2342"},转换成 int32 是{"point":158796070},数字转成 36 进制存储是{"point":"2mjjty"}。基本上省了个寂寞。
想要压缩就用 protobuf, flatbuffer, kiwi 这些,不要用 json
chendy
2021-09-16 16:36:07 +08:00
必须字符串的话
用 base64 的码表做 64 进制表示,然后全部拼进一个字符串里,两个字符是一个数字,四个字符是一个坐标,接收方自己解析成坐标数组就行
chenluo0429
2021-09-16 16:37:53 +08:00
一定要用 json,你还不如把字段名精简一下,可能比你折腾数字优化得还多些
jifengg
2021-09-16 16:44:23 +08:00
不知道你的“字符串里面有坐标数组”具体是什么格式,如果数字多的话,自定义一个二进制格式,传输之前 zip 压缩一下。
json 是格式统一方便应用解析,要尽可能节省的话用二进制+压缩。压缩会耗 CPU 可以酌情考虑加不加。
zjsxwc
2021-09-16 16:46:26 +08:00
而且 js 里整数存储比较奇葩,与主流语言使用 64 位存整数不同,js 是用 54 位来存储整数的。
在 js 中当然不存在 int32 了。

当然和楼主的需求不一样,因为用了 json 文本格式传输,楼主应该是想用字符表示上短一点数字,
我觉得可以先按楼主的算法两个数字变成一个数字,然后这个数字再用 36 进制表示,然后对 json 文本进行 jsonpack 压缩。


smartbot
2021-09-16 16:46:37 +08:00
protobuf, 应该是一种可选数据格式。
JustLookBy
2021-09-16 16:50:46 +08:00
@zjsxwc 好,我试试 谢谢

@chenluo0429 因为坐标数组上千个,所以优化还是比较有用的

@chendy 四个字符一个坐标的话也就是 16 字节一坐标,空间多了 3 倍,不是很高效
littlewing
2021-09-16 16:52:38 +08:00
ISO-8859-1
masterclock
2021-09-16 16:54:01 +08:00
1. 选择 CBOR 格式传输
2. 如果时大量数据,加压缩
chendy
2021-09-16 16:54:13 +08:00
@JustLookBy 但是相比于直接用数字已经砍掉一半了,还去掉了一堆逗号
zjsxwc
2021-09-16 16:57:50 +08:00
protobuf 应该是最省带宽
lasuar
2021-09-16 17:12:35 +08:00
@JustLookBy 行,位运算玩的挺溜
Vegetable
2021-09-16 17:18:29 +08:00
认为这个没什么意义,哪怕是传 binary,也省不下来多少,更何况你还有别的内容,还不如上一层 gzip 。
learningman
2021-09-16 17:18:29 +08:00
感觉拿 gzip 压一下就差不多了吧。。。
2i2Re2PLMaDnghL
2021-09-16 18:48:37 +08:00
我都怀疑你是特地凑好的
64*64=4096

如果限定在 ASCII 内,则只有 94 个字符可供表示(从 0x20 到 0x7F 再去掉引号和反斜杠),用 base94 表示的话
log_94 4096 = 1.83
仍然是四个字符表示一个坐标,和 base64 没区别

如果拓宽到 unicode,鉴于 UCS-2 会导致其他部分全部翻倍,得不偿失,所以还是 UTF-8
这就有个问题,UTF-8 编码效率非常不稳定,甚至可能三字节表示一个码位,看你的分布了

压缩有压缩的工具。
2i2Re2PLMaDnghL
2021-09-16 18:59:05 +08:00
压缩可能比 protobuf 更少。
比如如果你一千个坐标里面有五百个是同一个坐标,压缩能减很多。
joesonw
2021-09-16 19:18:46 +08:00
const ab = new ArrayBuffer(4);
const view = new Uint16Array(ab);
view[0] = x;
view[1] = y;
const socket = new WebSocket("ws://localhost:8080");
socket.binaryType = "arraybuffer";
socket.write(ab);

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/802322

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX