如何为地址结构生成唯一标识符
本文关键字:唯一 标识符 结构 地址 | 更新日期: 2023-09-27 18:08:06
我有一个描述地址的结构,它看起来像:
class Address
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public string Zip { get; set; }
public string Country { get; set; }
}
我正在寻找一种方法来创建一个唯一的标识符这个结构(我认为它也应该是一种类型的string
),这是依赖于所有的结构属性(例如,AddressLine1
的变化也会导致结构标识符的变化)。
我知道,我可以把所有的属性连接在一起,但是这样标识符太长了。我在找比这短得多的东西。
我还假设不同地址的数量不应超过100M。
关于如何生成这个标识符有什么想法吗?
提前感谢。
这个的史前史:
在数据库中有几个不同的表保存一些信息+地址数据。数据以类似于上面描述的格式存储。
不幸的是,现在将地址数据移动到一个单独的表中是非常昂贵的,但我希望将来能这样做。
我需要将一些附加属性与地址数据关联起来,并为此创建一个单独的表。这就是为什么我需要唯一标识地址数据
将所有字段序列化为一个大的二进制值。例如,使用适当的域分隔连接。
然后用足够长度的加密哈希值对该值进行哈希。我更喜欢256位,但128位也可以。对于好的哈希,碰撞是非常罕见的,对于像SHA-256这样的256位哈希,它们实际上是不可能的。
大多数人可能会这样想:
- 正常化地址
- 从规范化地址 创建一个哈希
- 做…
但是真正的问题出现在需要规范化地址的时候。例如,这些街道是相同的:
- place saint - franois 14"
- "place saint france "
- place st. francois 14"
- place st. francois 14;
- "14 Place saint france "
您可以尝试规范化文本的小写地址,删除重音/cedillas/破折号,并使用最接近的ASCII字符并解析数字以保留它,但仍然会有不可预见的例外。而且,一个不同的字符将产生一个完全不同的哈希值。
除非你所有的地址都是完全标准化的,否则我建议依赖于外部服务,如here.com
有三种使用服务的方法
- 使用该服务查找您的地址(长,晚,高度)的坐标,然后使用这些作为您的id(或3个id)
- 或者您可以使用该服务来查找地址并在数据库中保留自己的ID。缺点是他们不能保证他们的ID不会改变。
- 最后是使用他们的服务在他们的注册表中找到你的地址,然后使用他们的条目(将根据他们的标准规范化)来创建哈希。
我最喜欢的是1。因为我们仍然可以从坐标中找到地址(而这是不可能的哈希),而且,地址可能会改变(例如新的街道名称),而坐标不应该改变。最后但并非最不重要的是,您可能有两个完全不同的地址用于同一位置,这更容易使用坐标来协调它们。
下面是一个使用序列化,sha256哈希和base64编码(基于CodesInChaos答案)的完整示例:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Runtime.Serialization.Formatters.Binary;
namespace Uniq
{
[Serializable]
class Address
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public string Zip { get; set; }
public string Country { get; set; }
}
class MainClass
{
public static void Main (string[] args)
{
Address address1 = new Address(){AddressLine1 = "a1"};
Address address2 = new Address(){AddressLine1 = "a1"};
Address address3 = new Address(){AddressLine1 = "a2"};
string unique1 = GetUniqueIdentifier(address1);
string unique2 = GetUniqueIdentifier(address2);
string unique3 = GetUniqueIdentifier(address3);
Console.WriteLine(unique1);
Console.WriteLine(unique2);
Console.WriteLine(unique3);
}
public static string GetUniqueIdentifier(object obj){
if (obj == null) return "0";
SHA256 mySHA256 = SHA256Managed.Create ();
BinaryFormatter formatter = new BinaryFormatter ();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, obj);
byte[] hash = mySHA256.ComputeHash(stream.GetArray());
string uniqId = Convert.ToBase64String(hash);
return uniqId;
}
}
}
编辑:这是一个没有使用BinaryFormatter
的版本。您可以将空表示和字段分隔符替换为适合您需要的任何内容。
public static string GetUniqueIdentifier(object obj){
if (obj == null) return "0";
SHA256 mySHA256 = SHA256Managed.Create ();
StringBuilder stringRep = new StringBuilder();
obj.GetType().GetProperties()
.ToList().ForEach(p=>stringRep.Append(
p.GetValue(obj, null) ?? '¨'
).Append('^'));
Console.WriteLine(stringRep);
Console.WriteLine(stringRep.Length);
byte[] hash = mySHA256.ComputeHash(Encoding.Unicode.GetBytes(stringRep.ToString()));
string uniqId = Convert.ToBase64String(hash);
return uniqId;
}