字符串怎么承载 int32 信息? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
JustLookBy
V2EX    程序员

字符串怎么承载 int32 信息?

  •  
  •   JustLookBy 2021-09-16 16:19:12 +08:00 3574 次点击
    这是一个创建于 1539 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

    第 1 条附言    2021-09-16 20:24:37 +08:00
    先采用了 #5 #18 俩位的建议,用 base64 进行传输。

    一开始觉得不行是因为我对`utf8` 的匮乏了解,原来 utf8 并不是固定字节,我以前以为是固定 4 字节。。

    所以用 base64 以后实际上比理想体积增加了不到一倍而已,目前可以接受
    26 条回复    2021-09-17 10:12:23 +08:00
    lasuar
        1
    lasuar  
       2021-09-16 16:23:58 +08:00
    我有个问题,你这个 (x<<16)|y 操作可逆吗? 另外,你要节省就直接传 binary,别整 json 。
    JustLookBy
        2
    JustLookBy  
    OP
       2021-09-16 16:32:40 +08:00
    @lasuar 可逆啊,因为坐标值都小于 4,096

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

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

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


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

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

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

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

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

    压缩有压缩的工具。
    2i2Re2PLMaDnghL
        19
    2i2Re2PLMaDnghL  
       2021-09-16 18:59:05 +08:00
    压缩可能比 protobuf 更少。
    比如如果你一千个坐标里面有五百个是同一个坐标,压缩能减很多。
    joesonw
        20
    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:880");
    socket.binaryType = "arraybuffer";
    socket.write(ab);
    xiangyuecn
        21
    xiangyuecn  
       2021-09-16 20:05:54 +08:00
    存储前后坐标的差值,大概率能变成 0-9 的一位数,只需一个字符就能存储一个数字,2 个字符存储一个坐标,压缩比目测可以达到 30%

    之前写过一套经纬度坐标的压缩+解压代码,支持 6 位小数精度,150 来行代码,欢迎围观
    https://github.com/xiangyuecn/AreaCity-JsSpider-StatsGov/blob/master/assets/geo-echarts.js#L528-L707
    also24
        22
    also24  
       2021-09-16 20:07:16 +08:00
    @learningman #17
    我也觉得,反正都是重复字符,压缩效果应该很不错才对
    elfive
        23
    elfive  
       2021-09-16 20:16:31 +08:00 via iPhone
    数据压缩呀,lzma 压缩,我之前做的嵌入式程序,也是 json,也是传点坐标(两个 float,一般是上万个点),经过 lzma 压缩,能节约大概 80%的数据量。
    JustLookBy
        24
    JustLookBy  
    OP
       2021-09-16 20:21:04 +08:00
    @xiangyuecn
    @elfive 谢谢 我看下
    目前先用 base64,效果还算不错。
    ysc3839
        25
    ysc3839  
       2021-09-16 21:02:05 +08:00 via Android
    允许换掉 JSON 的话改用 Msgpack 吧,和 JSON 兼容。
    SmiteChow
        26
    SmiteChow  
       2021-09-17 10:12:23 +08:00
    msgpack
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3263 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 34ms UTC 11:14 PVG 19:14 LAX 03:14 JFK 06:14
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86