我有一个永远丢失的字符串。我唯一关于它的是一些魔术哈希数。现在我有了一个新的字符串,它可能与丢失的字符串相似或相等。我需要知道它有多接近。
Integer savedHash = 352736;
String newText = "this is new string";
if (Math.abs(hash(newText) - savedHash) < 100) {
// wow, they are very close!
}
有没有为此目的的算法?
PS。文本的长度不固定。
PPS。我知道通常的哈希码是如何工作的。我对一种不同的算法感兴趣,给我上面解释的功能。
购买力平价。在一个非常简单的场景中,这个hash()
方法看起来像:
public int hash(String txt) {
return txt.length();
}
答案 0 :(得分:4)
不,这不会起作用。哈希的相似性与原始字符串的相似性无关。实际上,2个不同的字符串完全有可能具有相同的散列。你可以肯定地说,如果散列不同,那么字符串是不同的。
[根据评论编辑,碰撞的可能性当然非常真实]
编辑以澄清:
如果您只有旧字符串的哈希值,那么您将无法找到该字符串的原始值。没有算法可以告诉你2个不同字符串的哈希值是否代表接近的字符串,即使有它也无济于事。即使您发现与旧字符串具有完全哈希匹配的字符串,仍然无法知道它是否是您的原始字符串,因为任意数量的字符串都可以生成相同的哈希值。事实上,有大量的字符串可以产生相同的哈希值。
[理论上这个庞大的数字实际上是无限的,但在任何真正的存储系统上,你都无法生成无数的字符串。在任何情况下,通过这种方法匹配未知字符串的可能性非常小,除非你的哈希值相对于输入字符串很大,即使这样你也需要强行通过每个可能的字符串]
答案 1 :(得分:4)
如果散列不匹配,则字符串不同。
如果哈希匹配,则字符串可能相同。
您可以从哈希值中推断出其他任何内容。
答案 2 :(得分:4)
标准哈希在这种情况下不起作用,因为紧密哈希值并不意味着关闭字符串。事实上,大多数散列函数都是为了给出非常不同的值,因此可以为任何给定的输入字符串集创建散列值的随机分布。
如果您可以访问这两个字符串,那么您可以使用某种字符串距离函数,例如Levenshtein distance。这将计算两个字符串之间的编辑距离,或者将一个字符串转换为另一个字符串所需的编辑数。
然而,在这种情况下,最好的方法可能是使用某种fuzzy hashing技术。这样您就不必存储原始字符串,仍然可以获得一些相似度。
答案 3 :(得分:1)
正如其他人所指出的那样,使用典型的哈希算法,它根本就不起作用。
然而,有一些人已经制定出至少与此类似的算法。举个例子,有一家名为“Xpriori”的公司,它有一些哈希(或类似哈希)的算法,允许这样的事情。他们会让你比较相似度,或者(例如)让你结合哈希hash(a) + hash(b) == hash(a+b)
(对于+
的某些定义,而不仅仅是简单的数字加法)。与大多数哈希一样,总是存在碰撞的可能性,因此您有可能出现误报(但通过选择哈希大小,您可以将该机会设置为任意小的值)。
因此,如果您正在处理现有数据,那么您可能会运气不好。如果你正在创建新的东西,并且想要这个订单的功能,那么它是可能的 - 虽然尝试自己做这件事认真地非常重要。
答案 4 :(得分:0)
没有。哈希的设计使输入字符串中的微小变化导致产生的哈希差异很大。这对于字典实现非常有用,并且可以验证文件的完整性(单个更改的位将导致完全不同的哈希)。所以不,这不是你可以用作不平等比较的某种东西。
答案 5 :(得分:0)
如果hashCodes不同,则它不能是相同的String,但是许多字符串可以具有相同的hashCode()。
根据字符串的性质,进行简单的比较可能比比较hashCode()更有效,它必须检查并对每个字符执行计算,而比较可以早期存储,例如如果长度不同或一看到不同的角色。
答案 6 :(得分:0)
根据定义,任何好的哈希算法都不会为类似的参数产生类似的哈希值。否则,它很容易破解。如果散列值“aaaa”看起来类似于“aaab”,那么这是一个糟糕的散列。我之前没有太多困难(有趣的谜题要解决!)但是你永远都不知道你的哈希算法很差。一个想法是什么?
如果你有时间,你可以通过散列每个可能的单词来强制解决这个问题。不优雅,但可能。如果您知道原始单词的长度,也会更容易。
如果它是一个标准的算法,比如MD5,你可以找到已经有大量源和哈希映射的网站,并以这种方式得到答案。试试http://hashcrack.com/
我们的开发人员离开后我成功使用了这个网站,我需要恢复密码。
干杯,
丹尼尔
答案 7 :(得分:0)
您可以将字符串视为一个非常大的数字,但这是关于您在一般情况下的能力范围。如果你有一个特定的问题域,你可以将字符串的表示压缩到更小而没有损失,但它仍然不会非常有用。
例如,如果您正在处理单个单词,则可以使用soundex来比较两个单词的相似程度......
使用传统哈希码可以做的最好的事情是比较两个字符串的相等性和可能的不等式。误报是可能的,但不会有误报。但是,你无法通过这种方式比较相似性。
答案 8 :(得分:0)
当对象稍微改变时,正常的哈希码会发生很大的变化。这是为了区分不同的物体而不关心它们的相似程度。因此答案是否定的
答案 9 :(得分:0)
在字符串的前半部分和后半部分之间计算Pearson correlation coefficient(如果字符串长度是奇数个字符,然后添加一些填充)并将此数字存储为32位浮点数。但我不确定这种方法有多可靠。
<强> == EDIT == 强>
这是C示例代码(未优化),它实现了这个想法(稍作修改):
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
float mean(char *str) {
char *x;
float sum = 0.0;
for(x=str; *x!='\0'; x++) {
sum += (float) *x;
}
return sum/strlen(str);
}
float stddev(char *str) {
char *x;
float sum = 0.0;
float u = mean(str);
for(x=str; *x!='\0'; x++) {
sum += ((float)*x - u)*((float)*x - u);
}
return sqrt(sum/strlen(str));
}
float covariance(char *str1, char *str2) {
int i;
int im = fmin(strlen(str1),strlen(str2));
float sum = 0.0;
float u1 = mean(str1);
float u2 = mean(str2);
for(i=0; i<im; i++) {
sum += ((float)str1[i] - u1)*((float)str2[i] - u2);
}
return sum/im;
}
float correlation(char *str1, char *str2) {
float cov = covariance(str1,str2);
float dev1 = stddev(str1);
float dev2 = stddev(str2);
return cov/(dev1*dev2);
}
float string_fingerprint(char *str) {
int len = strlen(str);
char *rot = (char*) malloc((len+1)*sizeof(char));
int i;
// rotate string by CHAR_COUNT/2
for(i=0; i<len; i++){
rot[i] = str[(i+len/2)%len];
}
rot[len] = '\0';
// now calculate correlation between original and rotated strings
float corr = correlation(str,rot);
free(rot);
return corr;
}
int main() {
char string1[] = "The quick brown fox jumps over the lazy dog";
char string2[] = "The slow brown fox jumps over the crazy dog";
float f1 = string_fingerprint(string1);
float f2 = string_fingerprint(string2);
if (fabs(f1 - f2) < 0.2) {
printf("wow, they are very close!\n");
}
return 0;
}
HTH!