将任何 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 表示形式。
对于这个问题,请假设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 表示形式。