Java随机生成字符串

6

我试图生成没有使用任何Random()函数的无意义单词。我想到可以使用当前时钟或鼠标坐标。我选择使用当前时钟。下面是我编写的代码。

private final char[] charray = {'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'};

private char getRandomCharacter(){
    return charray[random(charray.length)];
}

private int random(int value){
    value =(int) System.nanoTime()% 52;
    return value;
}

protected Randomizer(){
    boolean running = true;
    int count = 0;
    int max = 5;
    while(running){
        StringBuilder sb = new StringBuilder();
        int size = random(25) + random(25);
        for (int i = 0; i < size; i++) {
            sb.append(getRandomCharacter());
        }
        System.out.println("Random Line : " + sb.toString());

        if (count++ == max) {
            running = false;
            System.out.println("All of them are random.");
        }
    }
}

public static void main(String[] args) {
    new Randomizer();
}

我原本期望的输出是:

axdlMkjiIfjcmqQopv 等等..

但我得到的却像这样:

ZNNrrrUUUUxxxxbbbhhhLLLLoooRRRRRvvvYYYYBBBBfffI 或 JmmmPPKKKKnnnnRRBeeHHHHlllllOOOOrrrVVVVV

为什么会有太多连续的字符?是因为 nanoTime 太慢了吗?我之前用的是 currentTimeMillis,但它更糟糕。我找不出原因,也找不到任何关于如何使用当前时钟随机的资料。


3
这是一个作业问题吗?如果是,那么你已经展现了不错的努力。如果不是作业问题,我强烈建议您继续使用内置的Java Random类。伪随机数生成很难做到完美(即使在Java中最初的随机方法也没有做好),所以如果你试图重新发明这个轮子,你会让自己备受折磨。 - Bobulous
2
为什么要将“int value”传递给随机函数,只是为了分配新值并返回?输入参数的意义何在? - Sharon Ben Asher
2
此外,我不会期望 System.nanoTime() % 52 均匀分布。这基本上归结为每个 CPU 的 jiffy 不同,因此并非每个 CPU 在时间精度方面具有相同的粒度。 - Turing85
1
可能与平台有关。例如,在Mac OS上,我得到的是“OaWoVbYVNHxqeWMICACBzxlhYPHAtjkYPKveTWUWUXRTrmZVNDqAttjgaWMDAzWGEvpgcYLjSPHIENAs”。你使用的操作系统是什么? - Thomas Mueller
3
为什么你避免使用内置的Random类? - Mureinik
显示剩余15条评论
3个回答

2
您可以使用计时数据(除其他数据外)来“种子”随机数生成器,但仅使用计时数据来获取随机性并不容易。虽然这是可能的,但速度可能会非常慢。例如,您可以查看我在此处编写的代码,以了解如何使用其他数据来种子安全的随机实例(H2数据库,MathUtils.generateAlternativeSeed)。它使用:
  • System.currentTimeMillis()
  • System.nanoTime()
  • new Object().hashCode()
  • Runtime.freeMemory()、maxMemory()、totalMemory()
  • System.getProperties().toString()
  • InetAddress
  • 更多计时数据
这是为了种子一个安全的伪随机数生成器。这确保您即使在没有其他运行内容、不知道当前时间并且没有 UI 的系统上也能获得足够的熵。
但是,仅依赖于计时数据,就像您自己所看到的那样,是很困难的,因为它取决于操作系统、方法调用之间的时间、编译器和硬件。

非常感谢您的评论,它将帮助我更多地了解所有这些内容。再次感谢。 - Jarnsida

2

如果您将 charray 定义为 Character[] charray 并将其转换为列表:List<Character> chars = Arrays.asList(charray);,则可以获得更好的结果。

getRandomCharacter() 方法中使用此列表:

 private char getRandomCharacter(){
     Collections.shuffle(chars); // shuffle before each use 
     return chars.get(random(chars.size()));
 }

当然,还需要修复random
private int random(int value){
    return (int) System.nanoTime()% value;
}

输出:

随机行:tjnBUxTDeTulHfLqnEJBRBLXFqqikUYyrREzzwPwG
随机行:MZpzJbOyCaqraRPsQPSK
随机行:cEzKcsNHTmoVmT
随机行:CmGXpDHGOsUufSxxStDVQruR
随机行:XtFKmOAIisnXEdPikhAIcfzD
随机行:GVxdnwgWLKZvQIGuofCIhiiUbKsEbmAyzVfNNPM


问题要求“不使用任何Random()函数”,为什么这个回答被接受了?而且在洗牌后为什么要使用随机索引?它已经被洗牌了,为什么不使用char.get(0)呢? - Rad
@Rad - random不是内置方法,这可能是OP想要避免的,而不是特定的名为random的方法。它可以重命名为ghyusssqqq,功能仍将保持不变。 - Wai Ha Lee
1
我不太明白。如果我理解正确,作业是要重新实现随机功能。但是这个解决方案使用了Java内置的随机功能。 - Rad
@Rad,你说的get(0)是正确的。它应该也能正常工作。使用get(random)的好处需要进行测试。至于它是否满足了OP的需求,我将把这个决定留给他/她。 - c0der

1
仅使用时间来生成随机数存在问题,因为它限制了您请求“随机”数的频率,并且非常依赖于实现。
更好的方法是将时间用作种子,然后使用伪随机生成器,例如线性同余生成器。您可以在此答案中获得更多信息。请注意,此随机数生成器算法不安全,正如Thomas指出的那样,如果您想在所有系统中获得安全的RNG,则仅使用时间作为种子可能不足够。
因此,您的代码可能如下所示:
    private final char[] charray = {'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'};

private long seed;

private char getRandomCharacter() {
    return charray[random(charray.length)];
}

private int random(int value) {
    seed = (1103515245L * seed + 12345L) % 2147483648L;
    return (int)seed%value;
}

protected Randomizer() {
    boolean running = true;
    int count = 0;
    int max = 5;
    seed = System.nanoTime();
    while (running) {
        StringBuilder sb = new StringBuilder();
        int size = random(25) + random(25);
        for (int i = 0; i < size; i++) {
            sb.append(getRandomCharacter());
        }
        System.out.println("Random Line : " + sb.toString());

        if (count++ == max) {
            running = false;
            System.out.println("All of them are random.");
        }
    }
}

public static void main(String[] args) {
    new Randomizer();
}

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