生成与YouTube视频字符串类似的识别字符串的任何Java方式?

时间:2013-04-17 16:27:40

标签: java uniqueidentifier identifier

YouTube上的每个视频都有一个唯一的识别字符串,例如1cru2fzUlEc。

是否有任何Java方法可以生成接近它的东西?关闭我的意思是字符串是唯一的,短的,并使用数字和字母(区分大小写)。

我需要像YouTube使用的那样使用这样的字符串:在后端系统中识别记录。我正在做一个Java Web应用程序。我不想使用http://example.com?id=123的方法。

我知道Java的UUID实现可以产生类似的结果,但与YouTube相比,它太长了。

谢谢!

编辑1:

非常感谢大家的回复。您的所有输入都是有用的!似乎没有完美的解决方案。任何完美的(如果不是UUID)必须生成并检查(以避免重复)。我是对的吗?

我可以肯定地说,在制作自己的12个字符的视频字符串时,YouTube会遇到与我们Java用户相同的问题吗?

干杯!

编辑2:

我想使用全范围的字母数字字符而不仅仅是十六进制数字。我将使用Marcus Junius Brutus的解决方案。我觉得它足够直观和安全。从理论上讲,我将不得不检查每个生成的字符串,但我不会这样做,因为每次检查都是另一个数据库调用。我将为生成的字符串ID向表字段添加唯一约束。我可能会在第一次生成记录时让那个不幸的用户失败。他需要做的是回到表单再次填充并保存(希望不会因为重复的字符串值而第二次失败)。最初我将使用12-char字符串,我可以在需要时轻松增加长度。

我将使用此解决方案用于与同一后端数据库通信的分布式Web应用程序,这意味着同一应用程序的多个JVM。

这是我的解决方案,我希望它能奏效。

    String sampleAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    Random random = new Random();
    char[] buf = new char[12];
    for (int i = 0 ; i < 12 ; i++)
        buf[i] = sampleAlphabet.charAt(random.nextInt(sampleAlphabet.length()));
    return new String(buf);

谢谢大家的回复。它们都是可以接受的解决方案。我真的很感激。

祝你们好!

8 个答案:

答案 0 :(得分:3)

我认为最好的方法是使用数字和字母生成随机字符串,并在使用之前确保它在您的数据库中不存在。如果确实如此,只需生成另一个并再次检查,等等......

最不可能两次生成相同的字符串(但可能)。

或者正如你所说的那样你可以使用Java的UUID实现,但我想它有点长。

答案 1 :(得分:3)

你为什么不尝试这个?它满足您的所有需求。

https://github.com/peet/hashids.java

答案 2 :(得分:2)

您可以使用Base64编码自纪元以来的当前时间:

byte[] bytes = String.valueOf(System.currentTimeMillis()).getBytes();
String s = new sun.misc.BASE64Encoder().encode(bytes); 

请参阅https://ideone.com/f4cFy1了解演示。

答案 3 :(得分:2)

UUID是128位值的十六进制表示(插入“ - ”作为标点符号,就像逗号或空格用作十进制表示中的千位分隔符一样)。您可以像往常一样生成UUID,然后将128位值转换为更紧凑的表示形式,例如Base64Ascii85(a.k.a. Base85),从而保留UUID的优点并缩短标识符。这将使它减少到20个字符(使用Ascii85);不像YouTube的ID那么紧凑,但是UUID的36个字符可以节省相当多的费用。

如果仍然太长,则生成较少数量的随机字节(使用良好的PRNG)并转换为Ascii85。每四个字节的数据在Ascii85中生成5个字符。

编辑:在之前的评论中,我建议使用UUID的哈希值。这是它的工作方式。

  1. 确定代码中要包含的字符。 (假设它是a-z,A-Z和0-9,总共62个字符。)字符数是编码的基础 b
  2. 在base- b 编码中确定您想要的字符数 L 。计算可以用多个字符表示的值 n = b L 的值的数量。
  3. 生成128位UUID值 v 。可以把它想象成一个介于0和 N = 2 128 之间的数字。
  4. 使用简单的哈希函数(如描述的here)将 v 哈希值 h 范围[0, n < / em>的)。例如,您可以使用 h = floor(( v * n )/ N )。 (如果 n - 等效, b - 是2的幂,这只是一个二进制移位操作。)
  5. 使用步骤1中选择的字符集将 h 转换为base- b 表示。

答案 4 :(得分:1)

如果您想生成任意字符(例如全部字母数字而不仅仅是十六进制数字)或甚至篡改其频率,请创建一个包含所需示例字符的数组,然后:

String sampleAlphabet = "whatever";
Random random = new Random();
char[] bf = new char[length];
for (int i = 0 ; i < length ; i++)
    buf[i] = sampleAlphabet.charAt(random.nextInt(sampleAlphabet.length());
return new String(bf);

如果您愿意,请使用SecureRandom以提高安全性。

答案 5 :(得分:1)

UUID通常是以十六进制格式格式化的128位数字。

最大的128位数是2^128-12。如果以十六进制表示,则将变为32位字符长度log(2^128)/log(16) = 32

您可以定义一个自定义基数(例如包含0-9,a-z和A-Z),它将成为基数(62)10 + 26 + 26(在此基数位中区分大小写!)。

最大的128位数字将变为ceil(log(2^128)/log(62)) = 22位数。

如果它仍然很大,那么你应该使用较小的数字(不是128位)。

答案 6 :(得分:1)

生成随机字符使用此功能

public static String generateKey(int length) {
    String alphabet
            = new String("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); //9
    int n = alphabet.length();

    String result = new String();
    Random r = new Random();
    for (int i = 0; i < length; i++) {
        result = result + alphabet.charAt(r.nextInt(n));
    }
    return result;
}

答案 7 :(得分:0)

这是一个很好的方法来做你想做的事。 length是您想要的UUID的长度。重要的是要注意,当你缩短UUID的长度时,碰撞的几率会增加(感谢assylias在评论中提到这一点)。在使用之前,您一定要检查以确保它在数据库中不存在。如果确实如此,则只生成另一个。

public String getUUID(int length)
{
    return UUID.randomUUID().toString().replaceAll("-", "").substring(0, length);
}