4
votes

Is there a method that converts a string of text such as 'you' to a number other than

y = tuple('you')
for k in y:
  k = ord(k)

which only converts one character at a time?

4
You need to be able to get the text back after you convert it. - mikeLundquist
Get the text back from the integer? It's possible, but this sounds like a X-Y problem, what exactly are you trying to achieve? - Yu Hao

4 Answers

18
votes

In order to convert a string to a number (and the reverse), you should first always work with bytes. Since you are using Python 3, strings are actually Unicode strings and as such may contain characters that have a ord() value higher than 255. bytes however just have a single byte per character; so you should always convert between those two types first.

So basically, you are looking for a way to convert a bytes string (which is basically a list of bytes, a list of numbers 0–255) into a single number, and the inverse. You can use int.to_bytes and int.from_bytes for that:

import math
def convertToNumber (s):
    return int.from_bytes(s.encode(), 'little')

def convertFromNumber (n):
    return n.to_bytes(math.ceil(n.bit_length() / 8), 'little').decode()
>>> convertToNumber('foo bar baz')
147948829660780569073512294
>>> x = _
>>> convertFromNumber(x)
'foo bar baz'
2
votes
  1. You don't need to convert the string into tuple
  2. k is overwritten. Collect items using something like list comprehension:

>>> text = 'you'
>>> [ord(ch) for ch in text]
[121, 111, 117]

To get the text back, use chr, and join the characters using str.join:

>>> numbers = [ord(ch) for ch in text]
>>> ''.join(chr(n) for n in numbers)
'you'
1
votes

Treat the string as a base-255 number.

# Reverse the digits to make reconstructing the string more efficient
digits = reversed(ord(b) for b in y.encode())
n = reduce(lambda x, y: x*255 + y, digits)

new_y = ""
while n > 0:
    n, b = divmod(n, 255)
    new_y += chr(b)
assert y == new_y.decode()

(Note this is essentially the same as poke's answer, but written explicitly rather than using available methods for converting between a byte string and an integer.)

0
votes

I was trying to find a way to convert a numpy character array into a unique numeric array in order to do some other stuff. I have implemented the following functions including the answers by @poke and @falsetrue (these methods were giving me some trouble when the strings were too large). I have also added the hash method (a hash is a fixed sized integer that identifies a particular value.)

import numpy as np
def str_to_num(x):
    """Converts a string into a unique concatenated UNICODE representation

    Args:
        x (string): input string

    Raises:
        ValueError: x must be a string

    """
    if isinstance(x, str):
        x = [str(ord(c)) for c in x]
        x = int(''.join(x))
    else:
        raise ValueError('x must be a string.')

    return x


def chr_to_num(x):
    return int.from_bytes(x.encode(), 'little')


def char_arr_to_num(arr, type = 'hash'):
    """Converts a character array into a unique hash representation.

    Args:
        arr (np.array): numpy character array.
    """
    if type == 'unicode':
        vec_fun = np.vectorize(str_to_num)
    elif type == 'byte':
        vec_fun = np.vectorize(chr_to_num)
    elif type == 'hash':
        vec_fun = np.vectorize(hash)    
    out = np.apply_along_axis(vec_fun, 0, arr)
    out = out.astype(float)
    return out

a = np.array([['x', 'y', 'w'], ['x', 'z','p'], ['y', 'z', 'w'], ['x', 'w','y'], ['w', 'z', 'q']])
char_arr_to_num(a, type = 'unicode')
char_arr_to_num(a, type = 'byte')
char_arr_to_num(a, type = 'hash')