1

I'm trying to create a shortened ID for one of my models using the following method:

_char_map = string.ascii_letters+string.digits

def index_to_char(sequence):
    return "".join([_char_map[x] for x in sequence])

    def make_short_id(self):
        _id = self.id
        digits = []
        while _id > 0:
            rem = _id % 62
            digits.append(rem)
            _id /= 62
        digits.reverse()
        return index_to_char(digits) 

    @staticmethod
    def decode_id(string):
        i = 0
        for c in string:
            i = i * 64 + _char_map.index(c)
        return i

Where self.id is a uuid i.e. 1c7a2bc6-ca2d-47ab-9808-1820241cf4d4, but I get the following error:

rem = _id % 62 TypeError: not all arguments converted during string formatting

This method only seems to work when the id is an int.

How can I modify the method to shorten a uuuid and decode?

UPDATE:

Thank you for the help. I was trying to find a way create an encode and decode method that took a string, made it shorter then decode it back again. The methods above can never work with a string (uuid) as pointed out,

Prometheus
  • 32,405
  • 54
  • 166
  • 302

3 Answers3

6

The % operator is the string formatting or interpolation operator and does not return the remainder in Python when used with strings. It will try to return a formatted string instead.

I'm not sure what your input is, but try converting it using int so you can get the remainder of it.

Edit: I see your input now, not sure why I missed it. Here's one method of converting a UUID to a number:

import uuid
input = "1c7a2bc6-ca2d-47ab-9808-1820241cf4d4"
id = uuid.UUID(input)
id.int
# returns 37852731992078740357317306657835644116L

Not sure what you mean by "shorten", but it looks like you are trying to "base 62 encode" the UUID. If you use the function from this question you will end up with the following:

uuid62 = base62_encode(id.int)
# uuid62 contains 'RJChvUCPWDvJ7BdQKOw7i'

To get the original UUID back:

# Create a UUID again
id = uuid.UUID(int=base62_decode(uuid62))

id.hex
# returns '1c7a2bc6ca2d47ab98081820241cf4d4'           

str(id)
# returns '1c7a2bc6-ca2d-47ab-9808-1820241cf4d4'
Community
  • 1
  • 1
André Laszlo
  • 15,169
  • 3
  • 63
  • 81
  • I didn't vote you down, but the input is a uuid as in the OP, how can this be converted to an int? – Prometheus Jan 27 '15 at 11:22
  • 1
    I was only looking at how the input is _handled_ in the question. The OP is trying to convert a number by repeatedly doing remainder/division so I assumed that it was some sort of number. – André Laszlo Jan 27 '15 at 11:25
  • 1
    Ok that makes sense now. I will have to find a way to encode and decode a string to something shorter with a different method. Thanks for your help – Prometheus Jan 27 '15 at 11:29
  • I recommend against using `id` as a variable name unless you want to override builtin `id()`. – gruentee Oct 01 '20 at 12:59
2

_id is string

>>> 11 % 2
1

>>> "11" % 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting
Vivek Sable
  • 9,938
  • 3
  • 40
  • 56
0

I would suggest using base64.urlsafe_b64encode() from the standard library, rather than rolling your own base62_encode() function.

You first need to convert your hex string to a binary string:

binary_id = id.replace("-", "").decode("hex")

This binary string can the be encoded using the afore-mentioned function:

shortened_id = base64.urlsafe_b64encode(binary_id)
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841