【问题标题】:Python equivalent for JavaScript's DataViewPython 等效于 JavaScript 的 DataView
【发布时间】:2019-05-22 01:31:19
【问题描述】:

我从一个 base-64 编码的字符串加载一个字节数组,我想解析它。

但是值以不同的方式编码,我想复制 DataView 的行为。

例子:

function parse(data){
    view = new DataView(data.buffer);

    return {
        headerSize : view.getUint8(0),
        numberOfPlanes : view.getUint16(1, true),
        width: view.getUint16(3, true),
        height: view.getUint16(5, true),
        offset: view.getUint16(7, true)
    };
}

用法:

data = new Uint8Array([8, 96, 0, 0, 2, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
parse(data)

返回{headerSize: 8, numberOfPlanes: 96, width: 512, height: 256, offset: 8}

稍后我需要使用DataView.getFloat32

现在我有这样的东西:

def get_bin(a):
    ba = bin(a)[2:]
    return "0" * (8 - len(ba)) + ba


def getUInt16(arr, ind):
    a = arr[ind]
    b = arr[ind + 1]
    return int(get_bin(b) + get_bin(a), 2)

def getFloat32(arr, ind):
    return bin_to_float("".join(get(i) for i in arr[ind : ind + 4][::-1]))


def bin_to_float(binary):
    return struct.unpack("!f", struct.pack("!I", int(binary, 2)))[0]

但图书馆可以更高效、更通用

浮动示例:[111, 62, 163, 36] 应该产生 7.079574826789837e-17

【问题讨论】:

    标签: javascript python-3.x


    【解决方案1】:

    这应该涵盖了足够多的用例,或者至少可以让您达到可以进行细微更改的程度。希望您能在一定程度上遵循我的做法,但请随时提出问题。

    from functools import reduce
    import struct
    class DataView:
        def __init__(self, array, bytes_per_element=1):
            """
            bytes_per_element is the size of each element in bytes.
            By default we are assume the array is one byte per element.
            """
            self.array = array
            self.bytes_per_element = 1
    
        def __get_binary(self, start_index, byte_count, signed=False):
            integers = [self.array[start_index + x] for x in range(byte_count)]
            bytes = [integer.to_bytes(self.bytes_per_element, byteorder='little', signed=signed) for integer in integers]
            return reduce(lambda a, b: a + b, bytes)
    
        def get_uint_16(self, start_index):
            bytes_to_read = 2
            return int.from_bytes(self.__get_binary(start_index, bytes_to_read), byteorder='little')
    
        def get_uint_8(self, start_index):
            bytes_to_read = 1
            return int.from_bytes(self.__get_binary(start_index, bytes_to_read), byteorder='little')
    
        def get_float_32(self, start_index):
            bytes_to_read = 4
            binary = self.__get_binary(start_index, bytes_to_read)
            return struct.unpack('<f', binary)[0] # <f for little endian
    
    
    def parse(byte_array):
        d = DataView(byte_array)
        return {
            "headerSize": d.get_uint_8(0),
            "numverOfPlanes": d.get_uint_16(1),
            "width": d.get_uint_16(3),
            "hieght": d.get_uint_16(5),
            "offset": d.get_uint_16(7),
        }
    
    result = parse([8, 96, 0, 0, 2, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
    import json
    print(json.dumps(result, indent=2))
    
    d = DataView([111, 62, 163, 36])
    d.get_float_32(0)
    
    

    输出:

    {
      "headerSize": 8,
      "numverOfPlanes": 96,
      "width": 512,
      "hieght": 256,
      "offset": 8
    }
    7.079574826789837e-17
    

    【讨论】:

    • 谢谢! float32 实际上是我被卡住的地方,因为 int8 只是值,int16 正如你所看到的,我设法重现但float32 更难,如果你能看看我将不胜感激!
    • @ted 你能添加一个示例输入和输出,以便我检查我的工作吗?我不知道浮动通常是如何起作用的。
    • 但是你需要添加错误处理(特别是索引超出范围)。
    猜你喜欢
    • 1970-01-01
    • 2011-07-09
    • 1970-01-01
    • 2013-07-10
    • 2011-06-18
    • 2011-06-25
    • 2020-09-10
    相关资源
    最近更新 更多