Skip to content
Advertisement

How to encode list of numbers as base64

I have a list containing negative numbers, and want to encode the list with base64. How can I do that?

I tried:

l = [-10, -48, 100, -20]
bytes(l)

But I get the error:

ValueError: bytes must be in range(0, 256)

I expect the same output as my Java code:

byte[] bytes = {-10, -48, 100, -20};
String result = Base64Utils.encodeToUrlSafeString(bytes);
System.out.println(result); // 9tBk7A==

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

import base64


def to_unsigned(x, num_bits=8):
    uplim_uint = 2 ** num_bits
    return x % uplim_uint


l = [-10, -48, 100, -20]
base64.b64encode(bytes(to_unsigned(x) for x in l))
# b'9tBk7A=='

This can also be hard-coded for performance:

l = [-10, -48, 100, -20]
base64.b64encode(bytes(x % 64 for x in l))
# b'9tBk7A=='

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

def to_signed(x, num_bits=8):
    half = 2 ** (num_bits - 1)
    uplim_uint = 2 * half
    return x if x < half else x - uplim_uint


[to_signed(x) for x in base64.b64decode(b'9tBk7A==')]
# [-10, -48, 100, -20]

or, hard-coding the function:

[(x if x < 128 else x - 256) for x in base64.b64decode(b'9tBk7A==')]
# [-10, -48, 100, -20]
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement