如何使用 Unicode 和基数压缩文本长度,并能够将其恢复回来?

问题描述 投票:0回答:1

本文共有 44 个字符:

the quick brown fox jumped over the lazy dog

相同的文本只需 11 个 Unicode 字符即可表示:

񜥎񐟾𴬔񇒉𚫔𮹂𓻣񥯨񜥎𵁼񽤙

(这些字符看起来与“[]”相同,但它们都是不同的字符!)

这是因为 ASCII 字符的范围是 1-27(如果您只使用此字符集中的 27 个字符,则基数为 27

abcdefghijklmnopqrstuvwxyz 
),而 Unicode 字符的范围是 1-1114112,这意味着您可以在更大的内存中存储多个数字。如果您进行与指数相关的数学计算,则为数字。

例如,如果将每个字符转换为上述 27 个基本字符集中的索引,则文本

this
看起来像
[19, 7, 8, 18]
。如果您进行以下计算:

19 x 27 ^ 0 +  
7  x 27 ^ 1 +  
8  x 27 ^ 2 +  
18 x 27 ^ 3 = 360334

您将获得一个唯一的数字

360334
,该数字恰好在 1-1114112 范围内,因此您可以执行
chr(360334)
来获取 Unicode 字符
񗾎
。要返回,您可以执行
ord('񗾎')
来获得
360334
,您可以连续 divmod 来取回如下所示的数字:

360334 %  27 = 19
360334 // 27 = 13345
13345  %  27 = 7
13345  // 27 = 494
494    %  27 = 8
494    // 27 = 18
18     %  27 = 18
18     // 27 = 0 BREAK

问题是:如何在Python中将其作为转换和恢复函数?

这是我的尝试:

def power_sum(values, base, offset = 0):
    return sum(value * base ** (index + offset) for index, value in enumerate(values))

def convert_text(text, chars):
    base = len(chars)
    chars =  {char : index for index, char in enumerate(chars)}
    temp = []
    result = ''
    for index, char in enumerate(text):
        value = chars[char] # indexerror = missing that char in char set
        if power_sum(temp, base, 1) + value > 0x10FFFF: # U+10FFFF is max unicode code point
            result += chr(power_sum(temp, base))
            temp = [value]
        else:
            temp.append(value)
    result += chr(power_sum(temp, base))
    return result
    
def revert_text(text, chars):
    base = len(chars)
    chars = list(chars)
    result = ''
    for char in text:
        value = ord(char)
        while value:
            result += chars[int(value % base)]
            value //= base
    return result

chars = 'abcdefghijklmnopqrstuvwxyz '
print('Base:', len(chars), end = '\n\n')

texts = [
    'this',
    'the quick brown fox jumped over the lazy dog',
    'china'
]

for text in texts:
    print('Start text ({}): {}'.format(len(text), text))
    
    text = convert_text(text, chars)
    print('Unicode text ({}): {}'.format(len(text), text))
    
    text = revert_text(text, chars)
    print('Revert text ({}): {}'.format(len(text), text), end = '\n\n')

输出:

Base: 27

Start text (4): this
Unicode text (1): 񗾎
Revert text (4): this

Start text (44): the quick brown fox jumped over the lazy dog
Unicode text (11): 񽭂늺񒂴񿙳򁈌񊖞񇻉񿿸񽭂񷲄🖛
Revert text (44): the quick brown fox jumped over the lazy dog

Start text (5): china
Unicode text (2): 𿼎
Revert text (4): chin

由于某种原因,字符串

china
失败了。

python unicode ascii chr ord
1个回答
0
投票

不评论这种“压缩”的想法和原理(会有一些评论。但这不是你的问题)。

但是看看如何编码字符串“aaa”。

以 27 为基数,它是

27²×0 + 27×0 + 0
所以,0,对吗?

但这也是“a”的代码。或者“啊啊啊啊”。

由于您为最后一个字符添加了更多权重(不知何故,您在编码中是“小尾数”),因此您的情况与十进制数相同,但顺序相反(十进制数是“大尾数”)。 我的意思是,在十进制数中,开头的 0 表示较少。 001234 与 01234 或 1234 是一样的(在日常十进制中。不是在 C 或 python 中,它会触发八进制(对于 C)或者是语法错误(对于 python))。

在你的基数中,它的尾随 0 (或

a
)是没有意义的。所以
china
chin
chinaaaaa
是一样的。

© www.soinside.com 2019 - 2024. All rights reserved.