numpy 将一个长字节数组拆分为多个字符串数组

gxwragnw  于 2022-11-10  发布在  其他
关注(0)|答案(1)|浏览(153)

通常,在创建多个字符串数组时,我们可以执行如下操作

import numpy as np
np.array(["Hello world!", "good bye world!", "whatever world"])
>>> array(['Hello world!', 'good bye world!', 'whatever world'], dtype='<U15')

现在的问题是,我得到了一个来自外来C函数的长字节数组,如下所示:

b'Hello world!\x00<some rubbish bytes>good bye world!\x00<some rubbish bytes>whatever world\x00<some rubbish bytes>'

可以保证,每32个字节都是一个以空结尾的字符串(即,字符串的有效部分附加了一个\x00字节),并且我需要将这个长字节数组转换为类似于array(['Hello world!', 'good bye world!', 'whatever world'], dtype='<U15')的东西,最好是就地(即,没有内存复制)。
这就是我现在所做的:

for i in range(str_count):
    str_arr[i] = byte_arr[i * 32: (i+1) * 32].split(b'\x00')[0].decode('utf-8')
str_arr_np = np.array(str_arr),

它可以工作,但有点笨拙,而且没有就地完成(字节至少复制一次,如果不是两次的话)。有没有更好的办法?

zengzsys

zengzsys1#

如果你可以清零C端的数据,那么你可以使用np.frombuffer,它的效率将达到你合理预期的程度:
因此,如果您可以将数据置零,则可以使用numpy.frombuffer读取该数据,并且它可能是您合理期望获得的最高效率:

>>> raw = b'hello world\x00\x00\x00\x00\x00Good Bye\x00\x00\x00\x00\x00\x00\x00\x00'
>>> np.frombuffer(raw, dtype='S16')
array([b'hello world', b'Good Bye'], dtype='|S16')

当然,这会给您一个字节字符串,而不是Unicode字符串,尽管在您的情况下可能需要这样做。
注意,以上依赖于内置的去掉尾随空字节的行为,如果之后有垃圾,它将不起作用:

>>> data = b'hello world\x00aaaaGood Bye\x00\x00\x00\x00\x00\x00\x00\x00'
>>> np.frombuffer(data, dtype='S16')
array([b'hello world\x00aaaa', b'Good Bye'], dtype='|S16')

注意,这不应该复制,请注意:

>>> arr = np.frombuffer(raw, dtype='S16')
>>> arr
array([b'hello world', b'Good Bye'], dtype='|S16')
>>> arr[0] = b"z"*16
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: assignment destination is read-only

但是,如果目标不是只读的,那么假设您一开始就有一个bytearray

>>> raw = bytearray(raw)
>>> arr = np.frombuffer(raw, dtype='S16')
>>> arr[0] = b"z"*16
>>> arr
array([b'zzzzzzzzzzzzzzzz', b'Good Bye'], dtype='|S16')
>>> raw
bytearray(b'zzzzzzzzzzzzzzzzGood Bye\x00\x00\x00\x00\x00\x00\x00\x00')

相关问题