I have a list containing negative numbers, and want to encode the list with base64. How can I do that?
I tried:
JavaScript
x
3
1
l = [-10, -48, 100, -20]
2
bytes(l)
3
But I get the error:
JavaScript
1
2
1
ValueError: bytes must be in range(0, 256)
2
I expect the same output as my Java code:
JavaScript
1
4
1
byte[] bytes = {-10, -48, 100, -20};
2
String result = Base64Utils.encodeToUrlSafeString(bytes);
3
System.out.println(result); // 9tBk7A==
4
Advertisement
Answer
The error arises because Python expects unsigned 8-bit data, which can be obtained with the modulo %
operation:
unsigned == signed % 2 ** num_bits
JavaScript
1
12
12
1
import base64
2
3
4
def to_unsigned(x, num_bits=8):
5
uplim_uint = 2 ** num_bits
6
return x % uplim_uint
7
8
9
l = [-10, -48, 100, -20]
10
base64.b64encode(bytes(to_unsigned(x) for x in l))
11
# b'9tBk7A=='
12
This can also be hard-coded for performance:
JavaScript
1
4
1
l = [-10, -48, 100, -20]
2
base64.b64encode(bytes(x % 64 for x in l))
3
# b'9tBk7A=='
4
To convert this back you need loop through base64.b64decode()
and convert the unsigned data back to signed reverting the %
with a ternary conditional operator:
signed == unsigned if unsigned < 2 ** (num_bits - 1) else unsigned - 2 ** num_bits
JavaScript
1
9
1
def to_signed(x, num_bits=8):
2
half = 2 ** (num_bits - 1)
3
uplim_uint = 2 * half
4
return x if x < half else x - uplim_uint
5
6
7
[to_signed(x) for x in base64.b64decode(b'9tBk7A==')]
8
# [-10, -48, 100, -20]
9
or, hard-coding the function:
JavaScript
1
3
1
[(x if x < 128 else x - 256) for x in base64.b64decode(b'9tBk7A==')]
2
# [-10, -48, 100, -20]
3