Java中的8个字符唯一字符串

13

有没有办法在Java中生成8个字符长的随机且唯一的字符串?

String id = getRandomString();

然后id将会是例如wf41Av5g


1
如果你想要超过62^8个字符串(假设你只想要字母数字字符)的话,那么不行。你可能需要一个随机字符串,然后在已生成字符串的表中查找。 - user684934
6
定义 "unique":每次运行该方法,都会返回不同的字符串?或者所有字符彼此之间都不相同?还是其他情况? - amit
12个回答

28
你可以使用 RandomStringUtils
import org.apache.commons.lang.RandomStringUtils;
public class RandomStringUtilsTrial {
  public static void main(String[] args) {
    System.out.print("8 char string  >>>");
    System.out.println(RandomStringUtils.random(8, true, true));

  }
}

23
我很好奇,这个方法如何解决原帖作者的问题。文档中似乎没有任何保证唯一性的内容。 - taylorcressy

15

唯一性属性取决于您使用它的范围。Java当然可以生成随机字符串,但如果您想要一个通用唯一标识符,则可以使用UUID类。

String unique = UUID.randomUUID().toString();

3
很好,但我只需要8个字,否则我将不带任何疑问地使用它。 - danny.lesnik
2
UUID(通用唯一识别码)是有结构的,它们的字段以特定方式生成,并不是每个位都是同样独特的。这意味着你不能仅仅截取其中的随机位并期望它们保持唯一性。请参考Danny在Oliver的答案中对此问题的说明。 - Tom Anderson
2
@danny,即String eightChars = unique.substring(28); - Johan Sjöberg

14

如果唯一性很重要,那么简单地随机生成字符串是行不通的,因为无法避免碰撞。即使使用UUID,碰撞的概率也相当小。

你可以记录你已经使用过的字符串,在生成新的随机字符串时,检查记录以查看它是否重复,如果重复,则放弃它并重新尝试。

然而,我建议你不要生成随机数,而是保留计数器,并加密其输出以产生看起来像随机数的数字。如果你正确操作,这些数字永远不会发生碰撞。请参见我的早期回答Rossum的回答


6

您可以根据当前时间创建这个字符串。

例如:

2014 06 04 16 21 20 79 ---> 14 06 04 16 21 20 79

然后,您可以使用表格(http://en.wikipedia.org/wiki/Base64 - 请注意,所有的数字都小于59)将除最后两位以外的每两个数字翻译成一个字母数字字符。

然后你会得到:

14 - O
06 - G
04 - E
16 - Q
21 - V
20 - U

OGEQVU79 <- 正好8个字符。有点复杂,但如果您不经常调用函数,这种方法是有效的(间隔时间大于0.01秒)。


这并不保证唯一性 - 要考虑并发线程,甚至是单个线程在非常快速的连续操作中执行此操作。 - GabiM

1
public String getRandomString(int length, char[] characterSet) {
    StringBuilder sb = new StringBuilder();

    for (int loop = 0; loop < length; loop++) {
        int index = new Random().nextInt(characterSet.length);
        sb.append(characterSet[index]);
    }

    String nonce = sb.toString();
    return nonce;
}

1
作为以上答案均未确保唯一性,我决定再添加另一个答案。
首先,我们在一个数组中定义所有有效选项:
char[] chars = new char[]{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
        '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };

现在我们可以将算法变异为 数组的随机洗牌, 以获取前8个元素:
Random rnd = new Random();
int charsLength = chars.length;
int passLength = 8;
StringBuilder password = new StringBuilder();
for (int i = 0; i < passLength; i++)
{
    int index = rnd.nextInt(charsLength - i - 1);
    // Simple swap
    char a = chars[i + index];
    chars[i + index] = chars[i];
    chars[i] = a;
    password.append(a);
}

System.out.print(password);

它通过在数组的前8个位置中出现一个字符后,确保其独特性,该字符在下一轮中不是有效选择。
我得到的少量输出:
ifJjuYrR
NpY3TfIU
LGFm8Ng9
sV4Gctb7
4fyhlSuQ

嗨@Tomer,在这种情况下,获得重复数字的概率是多少?需要多少次,像百万、十亿等等。 - undefined

0

使用java.util.UUID的快速而简单的解决方案:

public String getRandomString(int length) {
    return UUID.randomUUID().toString().subSequence(0, length);
}

8
我生成了两个字符串:ff808181328864ba01328864bc590000和ff808181328864ba02328864bc5902300。如果我只取前八个字符,这两个字符串会变成相同的:( - danny.lesnik

0
请尝试以下代码:
private String uniqid() {
    Random random = new Random();
    String tag = Long.toString(Math.abs(random.nextLong()), 36);
    return tag.substring(0, 8);
}

我认为这并不完全做到了正确的事情,因为Long.toString会丢弃前导零。但是,您可以扩展代码以对短字符串进行零填充而不是修剪它们。 - Tom Anderson

0

我不知道是否有一种方法可以生成8位唯一的随机字符串,但我会创建一个离线密钥生成服务,不断生成随机密钥并将其插入到密钥表中,如果该密钥不存在于表中,每当您的在线应用程序需要密钥时,它可以从预先生成的密钥中获取。


你好,欢迎来到SO!请阅读tour如何撰写优秀答案?我认为这不是PO所询问的内容。 - Tomer Shetah

0

我知道这是一个旧帖子,但这可能对某些人有所帮助。

对于我来说,这个方法有效:

System.out.println(UniqueIdGenerator.fromBase10(System.currentTimeMillis()));

在同一个JVM上的每个毫秒都应该是唯一的。

使用:

public class UniqueIdGenerator {

 private static final String MIX_STRING = "abcdefghijklmnopqrstuvwxyz1234567890";

 private static final int MIX_STRING_LENGTH = MIX_STRING.length();

 public static String fromBase10(final long base10) {
    if (base10 == 0)
        return "0";

    long temp = base10;
    final StringBuilder sb = new StringBuilder();

    while (temp > 0) {
        temp = fromBase10(temp, sb);
    }
    return sb.reverse().toString();
 }

 private static Long fromBase10(final long base10, final StringBuilder sb) {
    final int rem = (int) (base10 % MIX_STRING_LENGTH);
    sb.append(MIX_STRING.charAt(rem));
    return base10 / MIX_STRING_LENGTH;
 }
}

你也可以改变 MIX_STRING 中的字符顺序,甚至添加大写字母或符号。


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