弦的双向"Hashing"

Two-way "Hashing" of string

本文关键字:Hashing      更新时间:2023-10-16

我想从字符串生成int,并能够生成它回来。有点像哈希函数,不过是双向函数。我想在我的应用程序中使用int作为ID,但希望能够在日志记录或调试的情况下将其转换回来。

:

int id = IDProvider::getHash("NameOfMyObject");
object * a = createObject(id);
...
if(error)
{
    LOG(IDProvider::getOriginalString(a->getId()), "some message");
}

我听说稍微修改的CRC32是快速和100%可逆的,但我找不到它,我不能自己写。

有什么提示吗?谢谢你!

编辑我刚刚找到了整个CRC32的来源:

Jason Gregory谈游戏引擎架构

报价:

"与任何散列系统一样,冲突是可能的(即两个不同的字符串可能以相同的散列码结束)。然而,使用合适的散列函数,我们几乎可以保证在游戏中可能使用的所有合理输入字符串都不会发生冲突。毕竟,一个32位哈希码代表了超过40亿个可能的值。所以如果我们的哈希函数能很好地将字符串事件分布在这个非常大的范围内,我们就不太可能发生碰撞。在Naughty Dog,我们使用了CRC-32算法的变体来处理字符串,在《神秘海域:德雷克的财富》开发的两年多时间里,我们没有遇到任何碰撞。"

将任意长度的字符串缩减为固定大小的int在数学上是不可能逆转的。参见皮孔原理。字符串的数量几乎是无限的,但只有2^32个32位整数。

32位哈希(假设int是32位)很容易发生冲突。所以它也不是一个好的唯一ID

有一些哈希函数允许您使用预定义的哈希创建消息,但它很可能不是原始消息。这被称为预映像。

对于你的问题,看起来最好的办法是创建一个字典,将整型id映射到字符串并返回。


当你哈希n个字符串时,要得到碰撞的可能性,请查看生日悖论。在这种情况下,最重要的属性是,一旦散列消息的数量接近可用散列值数量的平方根,就有可能发生冲突。所以对于32位整数,如果你哈希大约65000个字符串,很可能发生冲突。但如果你运气不好,这可能会发生得更早。

我正好有你需要的东西。它被称为"指针"。在这个系统中,"指针"总是唯一的,并且总是可以用来恢复字符串。它可以"指向"任何长度的字符串。作为奖励,它也具有与int相同的大小。您可以通过使用&操作数获得一个指向字符串的"指针",如我的示例代码所示:

#include <string>
int main() {
    std::string s = "Hai!";
    std::string* ptr = &s; // this is a pointer
    std::string copy = *ptr; // this retrieves the original string
    std::cout << copy; // prints "Hai!"
}

你需要的是加密。根据定义,哈希是单向的。您可以尝试使用一些值的加法/减法进行简单的异或加密。

    可逆哈希函数?为什么MD5哈希值是不可逆的?
  • 具有可逆性质的校验和/哈希函数
  • http://groups.google.com/group/sci.crypt.research/browse_thread/thread/ffca2f5ac3093255

你可以看看完美散列

http://en.wikipedia.org/wiki/Perfect_hash_function

只有在预先知道所有可能的字符串时才有效。在实践中,这样做是为了创建一个可以反向查找的有限范围的"哈希"映射。

一般来说,[哈希码+哈希算法]永远不足以获得原始值。然而,对于一个完美的散列,根据定义,冲突被排除在之外,所以如果源(值列表)是已知的,您可以获得源值。

gperf是一个用c/c++代码生成完美哈希值的知名老程序。还有很多(参见Wikipedia页面)

这是不可能的吗?

正如大家所提到的,不可能有一个"可逆的哈希值"。但是,也有其他选择(如加密)。

另一种是使用任何无损算法压缩/解压缩字符串。

这是一个简单的,完全可逆的方法,没有可能的碰撞