V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
raiz
V2EX  ›  Python

python 处理二进制数据正确方法是什么?

  •  
  •   raiz · 2016-03-04 14:04:06 +08:00 · 5217 次点击
    这是一个创建于 3218 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我有一个 tuple ,内容是 12 个 int , 范围是 0-255 , 相当 c 里的数组 unsigned char[12], 共 96bit 现在想按每 6 位切分这个数组为 16 个,也是 96bit 。
    采用方法:从低位开始,对字节位运算留 6 位,输出一个值,剩下的高位于下一个字节连接成新 byte ,重复直到够 16 个输出
    这种方法看起来很 c ,有 pythonic 的方法吗?

    13 条回复    2016-03-05 23:51:03 +08:00
    irainy
        1
    irainy  
       2016-03-04 15:26:51 +08:00
    py3>>> int("{:b}".format(255)[:6], base = 2)
    mulog
        2
    mulog  
       2016-03-04 15:59:28 +08:00
    你描述的不是很清楚啊 我假设是这样
    比如说你的 tuple 是 (1,127...)
    也就是 -> 00000001 01111111
    然后你说 从低位开始取六个嘛 那就是
    -> 100000
    然后高位和下一个字节的低位连起来 再取六个
    -> 00 1111
    然后
    - > 1110xx
    最后假设你需要把它再转回成 int

    乱写一个:
    # assuming t is the tuple holding 12 ints
    bits = "".join([bin(i)[2:].zfill(8)[::-1] for i in t])
    result = [int(bits[i:i+6], 2) for i in range(0, len(bits), 6)]
    wentian
        3
    wentian  
       2016-03-04 17:22:10 +08:00
    Python 有 struct 包啊, 我经常拿这个修改二进制文件
    楼上都是些什么答案
    fy
        4
    fy  
       2016-03-04 17:50:43 +08:00
    自带包 struct + 1 ,而且字节运算基本都看着比较笨,没什么 pythonic 不 pythonic 的
    上面的答案我也不是很懂
    chinuno
        5
    chinuno  
       2016-03-04 17:55:54 +08:00
    struct 好像只能一次处理 8 位
    要 6 位只能自己标记处理
    raiz
        6
    raiz  
    OP
       2016-03-04 19:31:15 +08:00
    Struct 的单位最小也是字节的,所以避免不了手动移位拼接
    ````
    SPLIT_SIZE_BIT = 6
    JOINED_SIZE_BIT = 8
    SPLIT_MASK = 0X3F
    SPLIT_LEN = 16

    ....
    def split(self, t):
    in_iter = iter(t)
    splited = []
    remain = 0
    remain_bit_cnt = 0
    while len(splited) < SPLIT_LEN:
    while remain_bit_cnt < SPLIT_SIZE_BIT:
    b = next(in_iter)
    b <<= remain_bit_cnt
    remain |= b
    remain_bit_cnt += JOINED_SIZE_BIT
    splited.append(remain & SPLIT_MASK)
    remain >>= SPLIT_SIZE_BIT
    remain_bit_cnt -= SPLIT_SIZE_BIT
    # print(splited)
    return splited
    ....
    ````
    leavic
        7
    leavic  
       2016-03-04 21:03:12 +08:00
    struct 包+ 1 ,我处理 hex 文件就靠这个
    test0x01
        8
    test0x01  
       2016-03-04 21:31:38 +08:00 via Android
    看需求吧,如果这个功能被调用的非常频繁的话我宁愿用 c 写出来。让 python 调用
    mulog
        9
    mulog  
       2016-03-04 21:38:28 +08:00
    @raiz 喏。。之前误解了你的需求 稍微改了一点
    比你贴上来的慢大概 50%左右 不过如果这部分性能很重要还不如直接 C 。。
    https://gist.github.com/mulog1990/50e1f3d8993db801663e
    savebox
        10
    savebox  
       2016-03-05 09:02:23 +08:00
    import base64, string
    t=range(12)
    E = string.maketrans('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',''.join([chr(c) for c in range(64)]))
    print [ord(c) for c in base64.b64encode("".join([chr(c) for c in t[::-1]])).translate(E)][::-1]

    速度应该更快一点
    calease
        11
    calease  
       2016-03-05 12:11:36 +08:00
    楼上上的用 re.findall('......', x)切分 string 可以 one liner
    [int(x, 2) for x in re.findall('......', "".join([bin(i)[2:].zfill(8) for i in t][::-1]))]
    ruoyu0088
        12
    ruoyu0088  
       2016-03-05 19:53:20 +08:00
    Python3 中可以使用 int.from_bytes 将一个字节序列转换为整数:

    import random

    data = [random.randint(0, 255) for _ in range(12)]
    x = int.from_bytes(bytearray(data), "big")
    r = [(x >> i) & 0x3f for i in range(90, -1, -6)]
    raiz
        13
    raiz  
    OP
       2016-03-05 23:51:03 +08:00
    @ruoyu0088 this one should be elegent and efficient
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5310 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 08:21 · PVG 16:21 · LAX 00:21 · JFK 03:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.