如何创建不包含数字的唯一标识符?

7

我想在.resx文件中使用某种唯一标识符,但它不允许键以数字开头。除了循环使用GUID直到找到以字母开头的一个之外,我想知道是否有其他类型的UID可以满足这个要求,例如不包含数字的UID或其他类型。

你有什么想法吗?

7个回答

14

如果您只想创建一个以字母开头的Guid,您可以像这样做:

var b = Guid.NewGuid().ToByteArray();
b[3] |= 0xF0;
return new Guid(b);

这将始终生成以十六进制数字 F 开头的 GUID。

要创建一个不包含任何数字的 Guid,您可以使用类似以下内容的代码:

return new Guid(Guid.NewGuid().ToByteArray()
    .Select(b => (byte)(((b % 16) < 10 ? 0xA : b) | 
                        (((b >> 4) < 10 ? 0xA : (b >> 4)) << 4)))
    .ToArray());

这将测试每个十六进制数字(每个字节两个)并将它强制转换为A,如果它小于A


上述两种解决方案都生成真正的 Guid 对象,尽管增加了一些限制会降低结果 GUID 的独特性(在第二个示例中更为明显)。如果你不关心输出是否是实际的 GUID,可以简单地将十六进制数字重新映射到其他内容,并将结果作为字符串返回,就像其他人建议的那样。顺便说一下,以下是我能想到的最短解决方案:

return String.Concat(Guid.NewGuid().ToString("N").Select(c => (char)(c + 17)));

这将十六进制数字0到9映射为字符AJ,将十六进制数字A - F映射为字符rw。它还生成一个没有连字符的字符串。例如:

Before: e58d0f329a2f4615b922ecf53dcd090a
After:  vFIuAwDCJrCwEGBFsJCCvtwFDutuAJAr

当然,如果您不喜欢这里的混合大小写,您可以将其转换为全部大写或小写。


2
@HamletHakobyan:即使是直接从Guid.NewGuid生成的GUID,没有任何篡改,也不能保证是唯一的。只是有非常非常非常高的概率。 - cHao
@HamletHakobyan 它肯定不像常规Guid那样独特,因为您将GUID限制为仅较小的一部分。即使是GUID也不能保证是唯一的,只是非常独特,以至于您不会合理地期望在宇宙的寿命内找到重复项。您需要多独特取决于应用程序。 - p.s.w.g
@HamletHakobyan UUID有多独特? - p.s.w.g
@HamletHakobyan:http://msdn.microsoft.com/en-us/library/system.guid.aspx 明确指出:“这样的标识符被重复的概率非常低。” - cHao
2
@Hamlet:除其他事项外,它意味着“有限数量”。事实上,它们不能保证是唯一的。它们足够接近,以至于在几乎所有情况下都可以依靠唯一性...但如果您需要绝对确定,您需要跟踪已经使用过的GUID。因为如果重复是生死攸关的问题,1/2^122比0大得多。 - cHao
显示剩余5条评论

3
如何生成一个唯一的数字并在其前面加上一个字母呢?因此,不再使用
```html

```

1234

您需要使用:
a1234

只要您选择的算法能够保证唯一性,这种做法就可以正常工作。这还可以让您去掉前缀,并在需要时将标识符作为数字进行操作。

2

您可以编写并使用伪随机序列生成器。这里是一个基本思路的示例:

class RandomLetterSequence { 
    private static Random r; 
    private static char MinChar = (char) 0x0061; 
    private static char MaxChar = (char) 0x007A; 

    public static string RandomSequence() { 
        return RandomSequence(32);  
    }

    public static string RandomSequence(int length) { 
        if (r == null)
            r = new Random(); 
        var sb = new StringBuilder(); 
        for (int i = length; i >= 0; i--) { 
            sb.Append((char)(r.Next(MinChar, MaxChar))); 
        }
        return sb.ToString();
    }
}

使用这种实现方式,将产生26 ^ 32个符合您要求的不同序列:

  • 与GUID类似,碰撞率极小
  • 仅包含字母

2

如果您不需要它成为有效的Guid(您提到“某种唯一标识符”),只需创建一个基于字符串的guid(使用Guid.NewGuid().ToString()),然后将第一个数字映射到一系列适当的字母,例如0=G,1=H,2=I等。


1

只需编写自己的类似GUID的生成器,有效字符应为a-z(也可以使用A-Z以增加概率数量)。


1
生成新的GUID,然后将0-9字符替换为g-p字符。

0

@p.s.w.g 提供了很好的解决方案。

你可以将他/她的建议写成扩展:

using System;
using System.Linq;

namespace YourApp.Extensions.GuidExtensions
{
    public static class Extension
    {
        public static Guid FirstLetter(this Guid obj)
        {
            var b = obj.ToByteArray();
            b[3] |= 0xF0;
            return new Guid(b);
        }

        public static Guid OnlyLetters(this Guid obj)
        {
            var ba = obj.ToByteArray();
            return new Guid(
                ba.Select(b => (byte)(((b % 16) < 10 ? 0xA : b) |
                                      (((b >> 4) < 10 ? 0xA : (b >> 4)) << 4)))
                  .ToArray()
            );
        }
    }
}

然后在应用程序的某个地方使用它:

// ...
using YourApp.Extensions.GuidExtensions;
// ...

class SomeClass {
    Guid SomeMethodWithFirstLetter() {
        return Guid.NewGuid().FirstLetter();
    }


    Guid SomeMethodWithOnlyLetters() {
        return Guid.NewGuid().OnlyLetters();
    }
}

我在想,将其实现为格式化程序而不是扩展是否更合适。 - Sinaesthetic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接