将任何 ASCII 字符串唯一编码为使用 ASCII 子集的字符串

Uniquely encode any ASCII string into a string that uses a subset of ASCII

对于这个问题,请假设python,但这并不一定重要。

假设您有一个任意的 ASCII 字符串,例如:

jrioj4oi3m_=\.,ei9#

保留大量细节,我需要将此字符串作为“标签”传递给另一个程序,但该程序不支持包含“特殊字符”甚至数字的“标签”。所以我试图将 ASCII 字符串编码为使用 ASCII 任意子集的字符串。

一个非常天真的解决方案是将原始字符串转换为二进制,然后将 0 转换为“a”,将 1 转换为“b”。这可以解决我的问题,但我想在这里学习更好的解决方案,成为更好的程序员。

首先,这个问题到底叫什么?

这不完全是散列问题,因为 IIRC 散列通常涉及编码成比原始字符串更短的字符串,并涉及冲突。

我需要没有 冲突,而且我真的不在乎编码字符串有多长,只要它比原始情况短即可。 (理想情况下,这将是给定子集的最短长度)

实际上,最好明确指定允许的字符集,然后使用通用编码算法进行编码。

解码也很高兴知道。

一个简单的解决方案是先转换为十六进制编码:

  • jrioj4oi3m_=.,ei9# => 6a72696f6a346f69336d5f3d2e2c65693923

然后将任何数字转换为非十六进制字母:

  • 6a72696f6a346f69336d5f3d2e2c65693923 => waxswzwfwatuwfwzttwdvftdsescwvwztzst

因此输出字符串的长度始终是输入字符串长度的两倍,并且只包含 a-z 范围内的字符。

这可以在 python 中轻松实现,如下所示:

>>> enc = str.maketrans('0123456789', 'qrstuvwxyz')
>>> dec = str.maketrans('qrstuvwxyz', '0123456789')
>>> s = 'jrioj4oi3m_=.,ei9#'
>>> x = s.encode('ascii').hex().translate(enc)
>>> x
'waxswzwfwatuwfwzttwdvftdsescwvwztzst'
>>> bytes.fromhex(x.translate(dec)).decode('ascii')
'jrioj4oi3m_=.,ei9#'

有趣的是,这实际上是一个非常简单且常见的数学问题:Base conversion。作为一名程序员,您可能至少在理论上知道如何在值的 2 进制、10 进制和 16 进制表示之间进行转换。有 96 个可打印的 ASCII 字符,因此任何 ASCII 字符串都可以被认为是一个(可能非常大的)值的 base 96 表示。如果您的标签只接受 64 个字符(例如,大写、小写、数字和其他 2 个字符),那么您只需将 base 96 表示形式转换为相同值的 base 64 表示形式。 解码只是将您的 base 64 表示形式转换回 base 96 表示形式。