我想获得String的唯一数字表示。我知道有很多方法可以做到这一点,我的问题是你认为哪种方式最好?我不想有负数 - 所以java中的hashcode()函数不是那么好,虽然我可以覆盖它...但我宁愿不要因为我不那么自信而且不想意外打破了一些东西。
My Strings都是语义网URIS。数字表示的原因是,当我在页面上显示URI的数据时,我需要将某些内容传递给查询字符串或放入我的javascript中的各个字段。当URI作为URI中的值时,URI本身太笨重并且看起来很糟糕。
基本上我想要一个名为Resource
的类,它看起来像这样
Resource{
int id;
String uri;
String value; // this is the label or human readable name
// .... other code/getters/setters here
public int getId(){
return id = stringToIntFunction();
}
private int stringToIntFunction(String uri){
// do magic here
}
}
如果出现以下情况,您能否建议执行此操作的功能:
还有其他重要问题我不考虑吗?
答案 0 :(得分:12)
如果你想要它是可逆的,那你就麻烦了。哈希设计是单向的。
特别是,假设int
有32位信息,而char
有16位信息,则需要可逆性意味着你只能拥有零个,一个或两个字符的字符串(和即使这是假设您很乐意将“”编码为“\ 0 \ 0”或类似的东西)。当然,这是假设你没有任何存储空间。如果你可以使用存储,那么只需按顺序存储数字......例如:
private int stringToIntFunction(String uri) {
Integer existingId = storage.get(uri);
if (existingId != null) {
return existingId.intValue();
}
return storage.put(uri);
}
这里storage.put()
会在内部增加一个计数器,将URI存储为与该计数器值相关联,然后返回它。我的猜测是,这不是你所追求的。
基本上,为了执行可逆加密,我使用标准加密库,首先将字符串转换为二进制格式(例如使用UTF-8)。我希望结果是byte[]
。
如果不必须是可逆的,我会考虑只取正常hashCode()
结果的绝对值(但将Integer.MIN_VALUE
映射到特定的,因为它的绝对值不能表示为int
)。
答案 1 :(得分:7)
哈希只是一种方式(这是它们具有固定长度的原因的一部分,无论输入大小如何)。如果你需要双向,你会看到类似Base64编码的东西。
为什么你不能有负数? URI来自哪里?他们在数据库中吗?为什么不使用数据库密钥ID?如果它们不在数据库中,您是否可以在给定一组变量/参数的情况下为用户生成它们? (因此查询字符串只包含诸如foo = 1& bar = 2之类的内容,并且您在服务器或JavaScript端生成URL)
答案 2 :(得分:3)
考虑到上面所做的所有重做(散列函数是单向),我会选择2种可能的解决方案:
答案 3 :(得分:2)
“唯一表示”意味着Java提供的string.hashcode将毫无用处 - 您很快就会遇到两个共享相同哈希码的URI。
任何双向方案都会导致一个笨重的字符串 - 除非您将URI存储在数据库中并使用记录ID作为唯一标识符。
就单向而言 - MD5哈希比简单哈希码更加独特(但绝不是唯一的) - 但根据你的定义可能会“笨拙”!
答案 4 :(得分:0)
Q1:如果你想从数字中恢复字符串,那么你可以使用:
1a:字符串的加密,除非先将字符串压缩,否则大小相同或更长。这将给出一组随机查找字节,可以显示为Base-64。
1b:数据库或地图,数字是地图/数据库中字符串的索引。
Q2:字符串不必是可恢复的。
这里有各种各样的想法。您可以以十六进制或Base-64显示散列以避免出现负号。 Base-64中唯一的非字母数字字符是'+','/'和'='。对于几乎唯一的哈希,您将需要一些加密大小,MD5(128位),SHA-1(160位)或SHA-2(256或512位)。
MD5哈希在十六进制中看起来像“d131dd02c5e6eec4693d9a0698aff95c”;散列越大,碰撞的可能性就越小。
Rossum的