我正在尝试开发一个系统,可以将我的字符串更改为唯一的整数值,这意味着例如单词“account”的加密数值为0891,并且没有其他单词可以转换为0891相同的转换过程,它确实不但是需要能够将生成的整数转换回字符串。
同时它将依赖于单词结构规则,意味着诸如“准确性”和“公告”之类的单词将具有大于0891的生成数字以及诸如“a”,“abacus”和“缩写”之类的单词“将生成的数字小于0891。
此应用程序的目的是提供类似于索引或主键的服务。我没有使用增量索引的原因是出于安全目的,并且是由于索引依赖于集合中的数据数量
(例如)
[0] A, [1] B, [2] C, [3] D, [4] E, [5] F
上述字母有各自对应的索引,E的索引为4
但是,如果数据突然增加或减少,则排序
[0] A, [1] AA, [2] AAB, [3] C, [4] D, [5] DA, [6] DZ, [7] E, [8] F
E现在的索引为7
每个单词必须具有唯一的独立整数等价物,并具有相应的权重。
我需要知道是否存在可以执行上述操作的算法。
任何帮助将不胜感激。
答案 0 :(得分:10)
除非您施加最大长度,否则这对您给出的约束是不可能的。
假设k("a")
和k("b")
是这两个字符串的代码。
根据您的约束,您正在寻找一个介于这两个值之间的唯一整数,但是k("a") < k("a....a") < k("b")
。由于存在无限数量的样式"a....a"
(和"akjhdsfkjhs"
)字符串,需要在两个代码之间进行拟合,这样的顺序保留一般,唯一,固定 - 长度代码不能存在任意长度的字符串。因为你需要尽可能多的整数作为字符串,并且因为字符串不受长度限制,所以这不起作用。
删除一般(所以不允许插入新字符串),唯一(允许碰撞 - 例如使用前四个字母作为代码!),无限长度(例如3个字符)或保留顺序属性。 / p>
答案 1 :(得分:8)
为简单起见,我假设a
到z
是单词中允许的唯一字符。
让我们分配最多2个字符串的数字:
String Value
a 0
aa 1
ab 2
...
az 26
b 27
ba 28
bb 29
...
bz 53
c 54
...
现在,通过观察,您应该能够理解,为了确定任何给定的较短长度字符串的偏移量,您需要允许的最大长度。我们假设我们知道这个数字。
为了简化算法,我们宁愿从27开始:(随意尝试从0开始计算出来,你需要一些特殊情况)
String Value
a 27
aa 28
ab 29
...
因此,基本上,最左边的字符会为27*(1-26)
(对于az)提供值,而右边的下一个字符(如果存在)会将1-26
(对于az)提供给值一个字符串。
现在可以概括地说,最左边的数字会贡献(1-26)*27^(len-1)
,下一个(1-26)*27^(len-2)
,依此类推,直到(1-26)*27^0
。
这引出了一些Java代码:
long result = 0;
for (int i = 0; i < s.length(); i++)
result += pow(27, MAX_LENGTH - i - 1)*(1 + s.charAt(i) - 'a');
测试输出:
a = 150094635296999121
aa = 155653695863554644
aaa = 155859586995649293
aaaa = 155867212593134280
aaaaa = 155867495022670761
abacus = 161447654121636735
abbreviation = 161763445236432690
account = 167509959568845165
accuracy = 167554723653128367
announcement = 230924421746611173
z = 3902460517721977146
是的,对于长达13个字符串的数字来说,这些是一些相当大的数字,但是,如果没有按顺序为实际字典中的单词分配数字,则不能做得更好(除了你可以从0开始,这是,相对而言,一个小差异),因为字母序列有很多可能性。
答案 2 :(得分:3)
对于唯一性,首先为字母分配素数:
A -> 2, B -> 3, C -> 5, D -> 7
等。
要计算单词中给定字母的“键”,请将素数提升为单词中位置索引的幂。要获得整个单词的“键”,请将所有字母键相乘。
例如单词CAB:
C -> 5 ^ 1 = 5
A -> 2 ^ 2 = 4
B -> 3 ^ 3 = 81
CAB -> 5 * 4 * 81 = 1620.
没有其他词会给你1620作为关键。
注意:您不必以A开始 - >&gt;只要您跟踪映射,就可以按顺序为素数字符分配素数2。另外请记住,这样的结果会很快变大。
但是,请记住有关安全性的其他评论 - 这不是一个特别安全的算法。
答案 3 :(得分:2)
如果对这些整数可以占用的字节数没有任何限制,那么每个字符的基础(例如Ascii)字节代码将为您提供整数表示。等价地,将0 = A,1 = B指定为Z = 25,然后单词本身是基数为26的整数。
答案 4 :(得分:1)
按递增顺序为每个字母分配唯一的素数值(无需订购)。
请注意:由于素数的乘法是一个唯一的结果,只能乘以这些数字,它会为每个单词提供唯一的值。
算法:
int hash = 0;
forEach (int i = 0 ; i < word.length ; i++)
{
hash *= (prime[c[i]] ** (length - i));
}
prime - 用于存储与每个
对应的素数值的数组启动(length - 1)以给出该字符出现位置的值以维护字典顺序。
此算法将提供足够大的值,超出您的阵列。
另外:单词较小的长度可能会比一些长度较大的单词给出较低的值,这可能会影响您的字典顺序但是我不确定为什么你要字典顺序因为唯一性会在这里维护。
答案 5 :(得分:1)
你可以这样做:
SEPARETOR = '000'
string_to_hash = "some_string"
hashed_result = int(SEPARETOR.join(list(str(ord(character)) for character in string_to_hash)))
享受!
答案 6 :(得分:0)
是的,但绝大多数没有。
是的,就像在随机答案中一样。通过设置基数26(或所有ASCII的基数128),理论上可以唯一地散列每个字符串。
另一方面,这是不切实际的,不仅数字对于大多数语言而言太大,而且这可能是一个令人难以置信的消耗过程。此外,如果允许字符串是无限的,那么也可以应用Cantor's diagonal argument的形式&#34; break&#34;这个算法。不可能创建一个具有基数aleph-one(字符串)的集合与一组基数aleph-null(整数)的一对一映射。
答案 7 :(得分:0)
长度为 s
的字符串 n
的一般形式的函数是:
hashCode(s) = s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
其中 ^
表示求幂。由于 Java 使用 32 位整数来保存哈希值,因此所有值都应保持原样。
如果要将字符串散列为小整数,可以使用以下C#
代码:
int StringToIntegerHash(string str)
{
int hash = 0;
str = GetTicketHash(str);
for(int i=0; i<str.Length;i++)
{
hash +=(int) ((int)str[i]) * Math.Pow(2, str.Length - i);
}
return hash;
}
string GetTicketHash(string str)
{
const string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
byte[] bytes = Encoding.UTF8.GetBytes(str);
SHA256Managed hashstring = new SHA256Managed();
byte[] hash = hashstring.ComputeHash(bytes);
char[] hash2 = new char[16];
// Note that here we are wasting bits of hash!
// But it isn't really important, because hash.Length == 32
for (int i = 0; i < hash2.Length; i++)
{
hash2[i] = chars[hash[i] % chars.Length];
}
return new string(hash2);
}