如何为地址结构生成唯一标识符

本文关键字:唯一 标识符 结构 地址 | 更新日期: 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位哈希,它们实际上是不可能的。

大多数人可能会这样想:

  1. 正常化地址
  2. 从规范化地址
  3. 创建一个哈希
  4. 做…

但是真正的问题出现在需要规范化地址的时候。例如,这些街道是相同的:

  • place saint - franois 14"
  • "place saint france "
  • place st. francois 14"
  • place st. francois 14;
  • "14 Place saint france "

您可以尝试规范化文本的小写地址,删除重音/cedillas/破折号,并使用最接近的ASCII字符并解析数字以保留它,但仍然会有不可预见的例外。而且,一个不同的字符将产生一个完全不同的哈希值。

除非你所有的地址都是完全标准化的,否则我建议依赖于外部服务,如here.com

有三种使用服务的方法

  1. 使用该服务查找您的地址(长,晚,高度)的坐标,然后使用这些作为您的id(或3个id)
  2. 或者您可以使用该服务来查找地址并在数据库中保留自己的ID。缺点是他们不能保证他们的ID不会改变。
  3. 最后是使用他们的服务在他们的注册表中找到你的地址,然后使用他们的条目(将根据他们的标准规范化)来创建哈希。

我最喜欢的是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;
}