Python 将代码点的numpy数组与字符串进行转换

Python 将代码点的numpy数组与字符串进行转换,python,arrays,string,numpy,Python,Arrays,String,Numpy,我有一个长的unicode字符串: alphabet = range(0x0FFF) mystr = ''.join(chr(random.choice(alphabet)) for _ in range(100)) mystr = re.sub('\W', '', mystr) 我想将其视为一系列代码点,因此目前我正在做以下工作: arr = np.array(list(mystr), dtype='U1') 我希望能够将字符串作为数字进行操作,并最终获得一些不同的代码点。现在我想反转转换

我有一个长的unicode字符串:

alphabet = range(0x0FFF)
mystr = ''.join(chr(random.choice(alphabet)) for _ in range(100))
mystr = re.sub('\W', '', mystr)
我想将其视为一系列代码点,因此目前我正在做以下工作:

arr = np.array(list(mystr), dtype='U1')
我希望能够将字符串作为数字进行操作,并最终获得一些不同的代码点。现在我想反转转换:

mystr = ''.join(arr.tolist())
这些转换相当快且可逆,但使用
列表
中介会占用不必要的空间

有没有一种方法可以在不首先转换为列表的情况下将unicode字符的numpy数组转换为Python字符串或从Python字符串转换为unicode字符

事后思考

我可以使
arr
显示为一个字符串,类似

buf = arr.view(dtype='U' + str(arr.size))
这将生成一个包含整个原始数据的1元素数组。反过来也是可能的:

buf.view(dtype='U1')

唯一的问题是结果的类型是
np.str
,而不是
str

我发现将字符串转换为数组的最快方法是

arr = np.array([mystr]).view(dtype='U1')
arr.view(dtype=f'U{arr.size}')[0]
将字符串转换为unicode代码点数组的另一种(较慢)方法基于:

查看的源代码显示,将
count
参数设置为字符串的长度将导致一次分配整个数组,而不是执行多次重新分配

要转换回字符串,请执行以下操作:

str(arr.view(dtype=f'U{arr.size}')[0])
在大多数情况下,没有必要最终转换为Python
str
,因为
np.str
str
的子类

arr.view(dtype=f'U{arr.size}')[0]
附录:缓冲区
与数组
的定时

一百

一万

一百万


fromiter
可以工作,但速度非常慢,因为它通过迭代器协议。将数据编码为UTF-32(按系统字节顺序)并使用以下命令更快:

我使用了
sys.byteorder
来确定是在
utf-32-le
中编码还是在
utf-32-be
中编码。另外,使用
bytearray
而不是
encode
可以获得可变的bytearray而不是不可变的bytes对象,因此生成的数组是可写的


至于反向转换,
arr.view(dtype=f'U{arr.size}')[0]
可以工作,但是使用会更快一些,并生成一个普通的字符串对象,从而避免了可能出现的奇怪的边缘情况,即
numpy.str
的行为不太像
str

In [72]: a = numpy.frombuffer(bytearray(x, codec), dtype='U1')

In [73]: type(a.view(dtype=f'U{a.size}')[0])
Out[73]: numpy.str_

In [74]: type(a.view(dtype=f'U{a.size}').item())
Out[74]: str

In [75]: %timeit a.view(dtype=f'U{a.size}')[0]
3.63 µs ± 34 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [76]: %timeit a.view(dtype=f'U{a.size}').item()
2.14 µs ± 23.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)


最后,请注意NumPy不像普通Python字符串对象那样处理空值。NumPy无法区分
'asdf\x00\x00\x00'
'asdf'
,因此,如果数据可能包含空代码点,则使用NumPy数组进行字符串操作是不安全的。

mystr=''.join(arr.tolist())
运行吗?
arr
不需要是字符串数组或类似的东西吗?如何:
np.frombuffer(mystr,dtype=np.uint8)
?@DanielMesejo。很抱歉,我删除了
.view(np.uint32)
部分,因为它非常不相关。@Divakar。我想我已经试过了,但是让我仔细检查一下
'.join(arr)
?我相当确定
U1
代表系统字节顺序。在我的例子中,它被翻译成
@madpysicator:我当时的印象是
>
我甚至不知道
的存在。肯定是选择了这个答案而不是我的。我在我的答案中添加了
arr=np.array([mystr]).view(dtype='U1')
。它似乎比其他任何选项都快得多。这次我确实检查了装置。在我看来,它在概念上与
.item()
相反,这很好。@mad物理学家:哦,对了,这是一个选择。我被复杂性搞得心烦意乱,完全忘记了可以直接将字符串传递给NumPy。这并不是更好的缩放。这是53.4毫秒,而733微秒。@user2357112。我会送出去的。去一所好学校。在那里我可以学习阅读。我自己也犯过很多同样的错误。
mystr = ''.join(chr(random.choice(range(1, 0x1000))) for _ in range(10000))

%timeit np.array([mystr]).view(dtype='U1')
4.33 µs ± 13.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit np.frombuffer(bytearray(mystr, 'utf-32-le'), dtype='U1')
10.9 µs ± 29.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
mystr = ''.join(chr(random.choice(range(1, 0x1000))) for _ in range(1000000))

%timeit np.array([mystr]).view(dtype='U1')
672 µs ± 1.64 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit np.frombuffer(bytearray(mystr, 'utf-32-le'), dtype='U1')
732 µs ± 5.22 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [56]: x = ''.join(chr(random.randrange(0x0fff)) for i in range(1000))

In [57]: codec = 'utf-32-le' if sys.byteorder == 'little' else 'utf-32-be'

In [58]: %timeit numpy.frombuffer(bytearray(x, codec), dtype='U1')
2.79 µs ± 47 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [59]: %timeit numpy.fromiter(x, dtype='U1', count=len(x))
122 µs ± 3.82 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [60]: numpy.array_equal(numpy.fromiter(x, dtype='U1', count=len(x)), numpy.fr
    ...: ombuffer(bytearray(x, codec), dtype='U1'))
Out[60]: True
In [72]: a = numpy.frombuffer(bytearray(x, codec), dtype='U1')

In [73]: type(a.view(dtype=f'U{a.size}')[0])
Out[73]: numpy.str_

In [74]: type(a.view(dtype=f'U{a.size}').item())
Out[74]: str

In [75]: %timeit a.view(dtype=f'U{a.size}')[0]
3.63 µs ± 34 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [76]: %timeit a.view(dtype=f'U{a.size}').item()
2.14 µs ± 23.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)