Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 生成用户友好的字母数字id(如业务id、SKU)的选项有哪些_C#_.net_Algorithm_Guid - Fatal编程技术网

C# 生成用户友好的字母数字id(如业务id、SKU)的选项有哪些

C# 生成用户友好的字母数字id(如业务id、SKU)的选项有哪些,c#,.net,algorithm,guid,C#,.net,Algorithm,Guid,以下是要求: 必须是字母数字,8-10个字符,以便用户友好。这些密钥将作为唯一密钥存储在数据库中。我使用guid作为主键,因此使用guid生成这些唯一id的选项更可取 我想到的是一个base-n转换器,它接受一个Guid并转换成一个8个字符的唯一字符串 短而轻的算法是首选,因为它经常被调用。您可能想尝试CRC32哈希算法。CRC32生成一个8个字符的字符串 你可以考虑它可以做字母和数字。 考虑从你的集合中删除I(眼睛)和O(OH),这样它们就不会与1(一)和0(零)混淆。有些人可能也会抱怨2和

以下是要求:

必须是字母数字,8-10个字符,以便用户友好。这些密钥将作为唯一密钥存储在数据库中。我使用guid作为主键,因此使用guid生成这些唯一id的选项更可取

我想到的是一个base-n转换器,它接受一个Guid并转换成一个8个字符的唯一字符串


短而轻的算法是首选,因为它经常被调用。

您可能想尝试CRC32哈希算法。CRC32生成一个8个字符的字符串

你可以考虑它可以做字母和数字。 考虑从你的集合中删除I(眼睛)和O(OH),这样它们就不会与1(一)和0(零)混淆。有些人可能也会抱怨2和Z。

如果你想要“用户友好型”,你可能想尝试使用完整的单词,而不是简单地将其简短/字母数字化,因此,类似于:

words = [s.strip().lower() for s in open('/usr/share/dict/canadian-english') if "'" not in s]
mod = len(words)

def main(script, guid):
    guid = hash(guid)

    print "+".join(words[(guid ** e) % mod] for e in (53, 61, 71))

if __name__ == "__main__":
    import sys
    main(*sys.argv)
产生如下输出:

oranjestad+compressing+wellspring
padlock+discommoded+blazons
pt+olenek+renews

这很有趣。否则,只需获取guid的前8-10个字符或guid的sha1/md5哈希值可能是最好的选择。

最简单的方法是每次需要值时都递增的计数器。八个(左零填充)数字为您提供了1亿个可能的值00000000到9999999(尽管您可能会插入空格或连字符以便于人类阅读,如000-000-00)

如果需要超过1亿个值,可以增加长度或在其他位置使用字母。使用A0A0A0到Z9Z9Z9可以提供超过45亿个可能值(4569760000)。获取一个长整数并生成这样的编码(最右边的数字是mod 10,最右边的字母是div 10,然后是mod 26,等等),这是一个很简单的代码。如果你有内存要消耗,最快的方法是将计数器转换成mod 260数组,并将每个mod 260值作为索引,转换成两个字符串的数组(“A0”,“A1”“A2”等通过“A9”、“B0”、“B1”等通过“Z9”)

基数36(在另一个答复中提到)的问题是,你不仅需要担心读者对相似字符的混淆(一对I,零对O,两对Z,五对S),还需要担心相邻字母的组合,这些字母可能会被读者视为拼写令人厌恶或淫秽的单词或缩写

8 characters - perfectly random - 36^8 = 2,821,109,907,456 combinations
10 characters - perfectly random - 36^10 = 3,656,158,440,062,976 combinations
GUID's - statistically unique* - 2^128 = 340,000,000,000,000,000,000,000,000,000,000,000,000 combinations
*

GUID->字符转换的问题;虽然GUID在统计上是唯一的,但通过使用任何子集,可以减少随机性并增加冲突的机会。您当然不想创建非unqiue SKU


解决方案1:

使用与对象和业务规则相关的数据创建SKU

i、 e.可能存在使对象唯一的一小部分属性组合。组合自然密钥的元素,编码并压缩它们以创建SKU。通常,您只需要一个日期时间字段(即CreationDate)和一些其他属性就可以实现这一点。在创建sku的过程中可能会有很多漏洞,但sku与您的用户更相关

假设:

Wholesaler, product name, product version, sku
Amazon,     IPod Nano,    2.2,             AMIPDNN22
BestBuy,    Vaio,         3.2,             BEVAIO32

解决方案2:

一种方法,它保留一系列数字,然后按顺序释放它们,并且从不两次返回相同的数字。你仍然可以在范围内留下洞。虽然您可能不需要生成足够的sku,但请确保您的需求考虑到这一点

实现方法是在具有计数器的数据库中有一个
表。计数器在事务中递增。重要的一点是,软件中的方法不是增加1,而是获取一个块。伪c#-代码如下

-- what the key table may look like
CREATE TABLE Keys(Name VARCHAR(10) primary key, NextID INT)
INSERT INTO Keys Values('sku',1)

// some elements of the class
public static SkuKeyGenerator 
{
    private static syncObject = new object();
    private static int nextID = 0;
    private static int maxID = 0;
    private const int amountToReserve = 100;

    public static int NextKey()
    {
        lock( syncObject )
        {
            if( nextID == maxID )
            {
                ReserveIds();
            }
            return nextID++;
        }
    }
    private static void ReserveIds()
    {
        // pseudocode - in reality I'd do this with a stored procedure inside a transaction,
        // We reserve some predefined number of keys from Keys where Name = 'sku'
        // need to run the select and update in the same transaction because this isn't the only
        // method that can use this table.
        using( Transaction trans = new Transaction() ) // pseudocode.
        {
             int currentTableValue = db.Execute(trans, "SELECT NextID FROM Keys WHERE Name = 'sku'");
             int newMaxID = currentTableValue + amountToReserve;
             db.Execute(trans, "UPDATE Keys SET NextID = @1 WHERE Name = 'sku'", newMaxID);

             trans.Commit();

             nextID = currentTableValue;
             maxID = newMaxID;
        }
    } 
这里的想法是保留足够的密钥,这样代码就不会经常访问数据库,因为获取密钥范围是一项昂贵的操作。您需要知道需要保留的密钥数量,以平衡密钥丢失(应用程序重新启动)与过快耗尽密钥并返回数据库之间的关系。这个简单的实现无法重用丢失的密钥

由于此实现依赖于数据库和事务,因此您可以让应用程序并发运行,并生成唯一的密钥,而无需经常访问数据库


注:以上内容大致基于第222页的键表。该方法通常用于生成主键,而不需要数据库标识列,但您可以看到如何根据自己的目的对其进行调整。

这可能是最好的选择,但不幸的是,128位GUID在基数36中仍然超过20个字符。也许GUID不是最好的起点。GUID可以从我的模型对象中随时获得,所以我相信这将非常方便。好的,你可以选择A-Z和A-Z,0-9,这是62的基数。也许这样会更好。但是,人们没有意识到不同大小写的项目是不同的,所以长时间使用Base62会遇到问题,但我最终使用base34,删除了一些难以辨认的字符。不,但前10个字符中的前10个字符给了你2**40个可能性(大约1万亿)的空间因此,根据要查找的标识符的数量,冲突的数量应该非常低。添加唯一性约束、回退和日志冲突。我喜欢你的建议。我唯一关心的是必须在应用程序中管理全局计数器。这就是我希望使用Guid作为序列的原因之一。