1890

我一直在寻找一种简单的Java 算法来生成伪随机字母数字字符串。在我的情况下,它将被用作唯一的会话/密钥标识符,“可能”在500K+一代人中是唯一的(我的需求实际上并不需要任何更复杂的东西)。

理想情况下,我将能够根据我的独特性需求指定长度。例如,生成的长度为 12 的字符串可能看起来像"AEYGF7K0DM1X".

4

44 回答 44

1617

算法

要生成随机字符串,请连接从一组可接受的符号中随机抽取的字符,直到字符串达到所需长度。

执行

这是一些用于生成随机标识符的相当简单且非常灵活的代码。阅读以下信息以获取重要的应用说明。

public class RandomString {

    /**
     * Generate a random string.
     */
    public String nextString() {
        for (int idx = 0; idx < buf.length; ++idx)
            buf[idx] = symbols[random.nextInt(symbols.length)];
        return new String(buf);
    }

    public static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    public static final String lower = upper.toLowerCase(Locale.ROOT);

    public static final String digits = "0123456789";

    public static final String alphanum = upper + lower + digits;

    private final Random random;

    private final char[] symbols;

    private final char[] buf;

    public RandomString(int length, Random random, String symbols) {
        if (length < 1) throw new IllegalArgumentException();
        if (symbols.length() < 2) throw new IllegalArgumentException();
        this.random = Objects.requireNonNull(random);
        this.symbols = symbols.toCharArray();
        this.buf = new char[length];
    }

    /**
     * Create an alphanumeric string generator.
     */
    public RandomString(int length, Random random) {
        this(length, random, alphanum);
    }

    /**
     * Create an alphanumeric strings from a secure generator.
     */
    public RandomString(int length) {
        this(length, new SecureRandom());
    }

    /**
     * Create session identifiers.
     */
    public RandomString() {
        this(21);
    }

}

使用示例

为 8 个字符的标识符创建一个不安全的生成器:

RandomString gen = new RandomString(8, ThreadLocalRandom.current());

为会话标识符创建安全生成器:

RandomString session = new RandomString();

创建一个带有易于阅读的打印代码的生成器。这些字符串比完整的字母数字字符串长,以补偿使用更少的符号:

String easy = RandomString.digits + "ACEFGHJKLMNPQRUVWXYabcdefhijkprstuvwx";
RandomString tickets = new RandomString(23, new SecureRandom(), easy);

用作会话标识符

生成可能唯一的会话标识符是不够的,或者您可以只使用一个简单的计数器。当使用可预测的标识符时,攻击者会劫持会话。

长度和安全性之间存在张力。较短的标识符更容易猜测,因为可能性较小。但是更长的标识符会消耗更多的存储空间和带宽。更大的符号集会有所帮助,但如果标识符包含在 URL 中或手动重新输入,则可能会导致编码问题。

会话标识符的随机性或熵的基本来源应该来自为密码学设计的随机数生成器。然而,初始化这些生成器有时会在计算上很昂贵或很慢,因此应该尽可能地重用它们。

用作对象标识符

并非每个应用程序都需要安全性。随机分配可以是多个实体在共享空间中生成标识符而无需任何协调或分区的有效方式。协调可能很慢,尤其是在集群或分布式环境中,当实体最终共享太小或太大时,分割空间会导致问题。

如果攻击者可能能够查看和操纵它们(就像在大多数 Web 应用程序中发生的那样),那么在没有采取措施使其不可预测的情况下生成的标识符应该受到其他方式的保护。应该有一个单独的授权系统来保护其标识符可以被攻击者在没有访问权限的情况下猜到的对象。

考虑到预期的标识符总数,还必须注意使用足够长的标识符以使冲突不太可能发生。这被称为“生日悖论”。冲突的概率 p大约为 n 2 /(2q x ),其中n是实际生成的标识符的数量,q是字母表中不同符号的数量,x是标识符的长度。这应该是一个非常小的数字,例如 2 ‑50或更少。

计算出来的结果表明,500k 15 个字符的标识符之间发生冲突的可能性约为 2 ‑52,这可能比来自宇宙射线等未检测到的错误的可能性更小。

与 UUID 的比较

根据他们的规范,UUID并非设计为不可预测的,也不应用作会话标识符。

标准格式的 UUID 占用大量空间:36 个字符仅代表 122 位熵。(并非“随机”UUID 的所有位都是随机选择的。)随机选择的字母数字字符串仅在 21 个字符中包含更多的熵。

UUID 不灵活;它们具有标准化的结构和布局。这是他们的主要美德,也是他们的主要弱点。与外部方合作时,UUID 提供的标准化可能会有所帮助。对于纯粹的内部使用,它们可能效率低下。

于 2008-09-03T04:04:24.647 回答
868

Java 提供了一种直接执行此操作的方法。如果你不想要破折号,它们很容易去掉。只需使用uuid.replace("-", "")

import java.util.UUID;

public class randomStringGenerator {
    public static void main(String[] args) {
        System.out.println(generateString());
    }

    public static String generateString() {
        String uuid = UUID.randomUUID().toString();
        return "uuid = " + uuid;
    }
}

输出

uuid = 2d7428a6-b58c-4008-8575-f05549f16316
于 2008-09-03T14:18:30.677 回答
620
static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static SecureRandom rnd = new SecureRandom();

String randomString(int len){
   StringBuilder sb = new StringBuilder(len);
   for(int i = 0; i < len; i++)
      sb.append(AB.charAt(rnd.nextInt(AB.length())));
   return sb.toString();
}
于 2008-10-01T11:36:54.490 回答
499

如果您乐于使用 Apache 类,您可以使用org.apache.commons.text.RandomStringGenerator( Apache Commons Text )。

例子:

RandomStringGenerator randomStringGenerator =
        new RandomStringGenerator.Builder()
                .withinRange('0', 'z')
                .filteredBy(CharacterPredicates.LETTERS, CharacterPredicates.DIGITS)
                .build();
randomStringGenerator.generate(12); // toUpperCase() if you want

Apache Commons Lang 3.6 以来,RandomStringUtils已弃用。

于 2008-09-04T11:14:46.040 回答
132

您可以为此使用Apache CommonsRandomStringUtils

RandomStringUtils.randomAlphanumeric(20).toUpperCase();
于 2012-07-20T10:23:18.087 回答
113

在一行中:

Long.toHexString(Double.doubleToLongBits(Math.random()));

来源:Java - 生成随机字符串

于 2009-09-17T15:22:57.530 回答
86

这很容易实现,无需任何外部库。

1. 加密伪随机数据生成 (PRNG)

首先,您需要一个加密 PRNG。Java 已经SecureRandom做到了这一点,并且通常使用机器上最好的熵源(例如/dev/random)。在这里阅读更多

SecureRandom rnd = new SecureRandom();
byte[] token = new byte[byteLength];
rnd.nextBytes(token);

注意: SecureRandom是 Java 中生成随机字节的最慢但最安全的方法。但是,我建议不要在这里考虑性能,因为它通常对您的应用程序没有真正的影响,除非您必须每秒生成数百万个令牌。

2. 可能值所需的空间

接下来,您必须决定您的令牌需要“多么独特”。考虑熵的唯一一点是确保系统能够抵抗蛮力攻击:可能值的空间必须如此之大,以至于任何攻击者只能在非可笑时间1尝试可忽略不计比例的值。

唯一标识符(例如随机)UUID具有 122 位熵(即 2^122 = 5.3x10^36) - 碰撞的机会是“*(...),因为有十亿分之一的重复机会,103 万亿必须生成版本 4 UUID 2 "。我们将选择 128 位,因为它完全适合 16 个字节,并且对于基本上每个但最极端的用例而言,它被认为是唯一的,而且您不必考虑重复。这是一个简单的熵比较表,包括对生日问题的简单分析。

代币大小比较

对于简单的要求,8 或 12 字节的长度可能就足够了,但 16 字节的长度是“安全的”。

基本上就是这样。最后一件事是考虑编码,以便可以将其表示为可打印的文本(读取,a String)。

3. 二进制转文本编码

典型的编码包括:

  • Base64每个字符编码 6 位,产生 33% 的开销。幸运的是, Java 8+Android中有标准实现。对于较旧的 Java,您可以使用众多第三方库中的任何一个。如果您希望您的令牌是 URL 安全的,请使用 RFC4648 的URL 安全版本(大多数实现通常都支持该版本)。使用填充编码 16 个字节的示例:XfJhfv3C0P6ag7y9VQxSbw==

  • Base32每个字符编码 5 位,产生 40% 的开销。这将使用A-Zand 2-7,使其在不区分大小写的字母数字的同时具有合理的空间效率。JDK中没有任何标准实现。示例编码 16 字节,没有填充:WUPIL5DQTZGMF4D3NX5L7LNFOY

  • Base16(十六进制)每个字符编码四位,每个字节需要两个字符(即,16 个字节创建一个长度为 32 的字符串)。因此,十六进制的空间效率低于,但在大多数情况下(URL)使用它是安全的,Base32因为它只使用0-9and 。示例编码 16 字节:. 在此处查看有关转换为十六进制的 Stack Overflow 讨论AF4fa3dd0f57cb3bf331441ed285b27735

Base85和奇异的Base122等其他编码具有更好/更差的空间效率。您可以创建自己的编码(基本上这个线程中的大多数答案都可以),但如果您没有非常具体的要求,我建议您不要这样做。在 Wikipedia 文章中查看更多编码方案。

4. 总结和例子

  • 采用SecureRandom
  • 使用至少 16 个字节 (2^128) 的可能值
  • 根据您的要求编码(通常hexbase32如果您需要它是字母数字)

  • ...使用您的自制编码:如果其他人看到您使用的标准编码而不是奇怪循环一次创建字符,则他们可以更好地维护和阅读。
  • ... 使用 UUID:它不能保证随机性;你在浪费 6 位熵并且有一个冗长的字符串表示

示例:十六进制令牌生成器

public static String generateRandomHexToken(int byteLength) {
    SecureRandom secureRandom = new SecureRandom();
    byte[] token = new byte[byteLength];
    secureRandom.nextBytes(token);
    return new BigInteger(1, token).toString(16); // Hexadecimal encoding
}

//generateRandomHexToken(16) -> 2189df7475e96aa3982dbeab266497cd

示例:Base64 令牌生成器(URL 安全)

public static String generateRandomBase64Token(int byteLength) {
    SecureRandom secureRandom = new SecureRandom();
    byte[] token = new byte[byteLength];
    secureRandom.nextBytes(token);
    return Base64.getUrlEncoder().withoutPadding().encodeToString(token); //base64 encoding
}

//generateRandomBase64Token(16) -> EEcCCAYuUcQk7IuzdaPzrg

示例:Java CLI 工具

如果你想要一个现成的 CLI 工具,你可以使用dice

示例:相关问题 - 保护您当前的身份

如果您已经有一个可以使用的 id(例如,long您的实体中的合成),但不想发布内部值,您可以使用此库对其进行加密和混淆:https ://github.com/ patrickfav/id-mask

IdMask<Long> idMask = IdMasks.forLongIds(Config.builder(key).build());
String maskedId = idMask.mask(id);
// Example: NPSBolhMyabUBdTyanrbqT8
long originalId = idMask.unmask(maskedId);
于 2017-05-28T12:06:11.400 回答
43

使用Dollar应该很简单:

// "0123456789" + "ABCDE...Z"
String validCharacters = $('0', '9').join() + $('A', 'Z').join();

String randomString(int length) {
    return $(validCharacters).shuffle().slice(length).toString();
}

@Test
public void buildFiveRandomStrings() {
    for (int i : $(5)) {
        System.out.println(randomString(12));
    }
}

它输出如下内容:

DKL1SBH9UJWC
JH7P0IT21EA5
5DTI72EO6SFU
HQUMJTEBNF7Y
1HCR6SKYWGT7
于 2010-02-01T17:12:41.660 回答
37

这是Java:

import static java.lang.Math.round;
import static java.lang.Math.random;
import static java.lang.Math.pow;
import static java.lang.Math.abs;
import static java.lang.Math.min;
import static org.apache.commons.lang.StringUtils.leftPad

public class RandomAlphaNum {
  public static String gen(int length) {
    StringBuffer sb = new StringBuffer();
    for (int i = length; i > 0; i -= 12) {
      int n = min(12, abs(i));
      sb.append(leftPad(Long.toString(round(random() * pow(36, n)), 36), n, '0'));
    }
    return sb.toString();
  }
}

这是一个示例运行:

scala> RandomAlphaNum.gen(42)
res3: java.lang.String = uja6snx21bswf9t89s00bxssu8g6qlu16ffzqaxxoy
于 2008-09-03T04:37:02.040 回答
35

一个简短而简单的解决方案,但它只使用小写字母和数字:

Random r = new java.util.Random ();
String s = Long.toString (r.nextLong () & Long.MAX_VALUE, 36);

大小约为 12 位,以 36 为基数,无法进一步改进。当然,您可以附加多个实例。

于 2012-04-17T10:08:46.840 回答
32

令人惊讶的是,这里没有人建议过,但是:

import java.util.UUID

UUID.randomUUID().toString();

简单的。

这样做的好处是 UUID 很好,很长,并且保证几乎不可能发生冲突。

维基百科对此有很好的解释

“……只有在接下来的 100 年每秒生成 10 亿个 UUID 之后,仅创建一个副本的概率约为 50%。”

前四位是版本类型,两位是变体,所以你得到 122 位随机数。因此,如果您愿意,可以从末尾截断以减小 UUID 的大小。不建议这样做,但您仍然有大量随机性,足以轻松处理 500k 条记录。

于 2012-10-25T15:45:41.183 回答
19

Java 8 中的替代方案是:

static final Random random = new Random(); // Or SecureRandom
static final int startChar = (int) '!';
static final int endChar = (int) '~';

static String randomString(final int maxLength) {
  final int length = random.nextInt(maxLength + 1);
  return random.ints(length, startChar, endChar + 1)
        .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
        .toString();
}
于 2014-11-25T07:23:10.740 回答
12
import java.util.Random;

public class passGen{
    // Version 1.0
    private static final String dCase = "abcdefghijklmnopqrstuvwxyz";
    private static final String uCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final String sChar = "!@#$%^&*";
    private static final String intChar = "0123456789";
    private static Random r = new Random();
    private static StringBuilder pass = new StringBuilder();

    public static void main (String[] args) {
        System.out.println ("Generating pass...");
        while (pass.length () != 16){
            int rPick = r.nextInt(4);
            if (rPick == 0){
                int spot = r.nextInt(26);
                pass.append(dCase.charAt(spot));
            } else if (rPick == 1) {
                int spot = r.nextInt(26);
                pass.append(uCase.charAt(spot));
            } else if (rPick == 2) {
                int spot = r.nextInt(8);
                pass.append(sChar.charAt(spot));
            } else {
                int spot = r.nextInt(10);
                pass.append(intChar.charAt(spot));
            }
        }
        System.out.println ("Generated Pass: " + pass.toString());
    }
}

这只是将密码添加到字符串中......是的,它运作良好。看看……很简单;我写的。

于 2012-04-16T15:48:41.787 回答
12
public static String generateSessionKey(int length){
    String alphabet =
        new String("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); // 9

    int n = alphabet.length(); // 10

    String result = new String();
    Random r = new Random(); // 11

    for (int i=0; i<length; i++) // 12
        result = result + alphabet.charAt(r.nextInt(n)); //13

    return result;
}
于 2012-10-09T04:40:48.653 回答
12

使用 UUID 是不安全的,因为 UUID 的某些部分根本不是随机的。erickson的过程非常简洁,但它不会创建相同长度的字符串。以下代码段应该足够了:

/*
 * The random generator used by this class to create random keys.
 * In a holder class to defer initialization until needed.
 */
private static class RandomHolder {
    static final Random random = new SecureRandom();
    public static String randomKey(int length) {
        return String.format("%"+length+"s", new BigInteger(length*5/*base 32,2^5*/, random)
            .toString(32)).replace('\u0020', '0');
    }
}

为什么选择length*5?让我们假设一个长度为 1 的随机字符串的简单情况,即一个随机字符。要获得包含所有数字 0-9 和字符 az 的随机字符,我们需要一个介于 0 和 35 之间的随机数来获取每个字符之一。

BigInteger提供了一个构造函数来生成一个随机数,均匀分布在 range0 to (2^numBits - 1)中。不幸的是,35 不是 2^numBits - 1 可以接收的数字。

所以我们有两个选择:要么选择2^5-1=31要么2^6-1=63。如果我们选择2^6,我们会得到很多“不必要的”/“更长的”数字。因此2^5是更好的选择,即使我们丢失了四个字符 (wz)。现在要生成一定长度的字符串,我们可以简单地使用一个2^(length*numBits)-1数字。最后一个问题,如果我们想要一个具有一定长度的字符串,random 可以生成一个小数,所以长度不满足,所以我们必须将字符串填充到它所需的长度前面加上零。

于 2015-07-03T22:07:48.560 回答
10

我找到了生成随机十六进制编码字符串的解决方案。提供的单元测试似乎符合我的主要用例。虽然,它比提供的其他一些答案稍微复杂一些。

/**
 * Generate a random hex encoded string token of the specified length
 *  
 * @param length
 * @return random hex string
 */
public static synchronized String generateUniqueToken(Integer length){ 
    byte random[] = new byte[length];
    Random randomGenerator = new Random();
    StringBuffer buffer = new StringBuffer();

    randomGenerator.nextBytes(random);

    for (int j = 0; j < random.length; j++) {
        byte b1 = (byte) ((random[j] & 0xf0) >> 4);
        byte b2 = (byte) (random[j] & 0x0f);
        if (b1 < 10)
            buffer.append((char) ('0' + b1));
        else
            buffer.append((char) ('A' + (b1 - 10)));
        if (b2 < 10)
            buffer.append((char) ('0' + b2));
        else
            buffer.append((char) ('A' + (b2 - 10)));
    }
    return (buffer.toString());
}

@Test
public void testGenerateUniqueToken(){
    Set set = new HashSet();
    String token = null;
    int size = 16;

    /* Seems like we should be able to generate 500K tokens 
     * without a duplicate 
     */
    for (int i=0; i<500000; i++){
        token = Utility.generateUniqueToken(size);

        if (token.length() != size * 2){
            fail("Incorrect length");
        } else if (set.contains(token)) {
            fail("Duplicate token generated");
        } else{
            set.add(token);
        }
    }
}
于 2008-09-03T14:22:23.913 回答
9
  1. 根据您的要求更改字符串字符。

  2. 字符串是不可变的。这里StringBuilder.append比字符串连接更有效。


public static String getRandomString(int length) {
    final String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_+";
    StringBuilder result = new StringBuilder();

    while(length > 0) {
        Random rand = new Random();
        result.append(characters.charAt(rand.nextInt(characters.length())));
        length--;
    }
    return result.toString();
}
于 2014-02-06T13:15:18.227 回答
8
import java.util.Date;
import java.util.Random;

public class RandomGenerator {

  private static Random random = new Random((new Date()).getTime());

    public static String generateRandomString(int length) {
      char[] values = {'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','0','1','2','3',
               '4','5','6','7','8','9'};

      String out = "";

      for (int i=0;i<length;i++) {
          int idx=random.nextInt(values.length);
          out += values[idx];
      }
      return out;
    }
}
于 2011-10-19T04:36:44.080 回答
8

我真的不喜欢任何关于“简单”解决方案的答案:S

我会选择一个简单的 ;),纯 Java,一个衬里(熵基于随机字符串长度和给定的字符集):

public String randomString(int length, String characterSet) {
    return IntStream.range(0, length).map(i -> new SecureRandom().nextInt(characterSet.length())).mapToObj(randomInt -> characterSet.substring(randomInt, randomInt + 1)).collect(Collectors.joining());
}

@Test
public void buildFiveRandomStrings() {
    for (int q = 0; q < 5; q++) {
        System.out.println(randomString(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")); // The character set can basically be anything
    }
}

或者(更易读的旧方式)

public String randomString(int length, String characterSet) {
    StringBuilder sb = new StringBuilder(); // Consider using StringBuffer if needed
    for (int i = 0; i < length; i++) {
        int randomInt = new SecureRandom().nextInt(characterSet.length());
        sb.append(characterSet.substring(randomInt, randomInt + 1));
    }
    return sb.toString();
}

@Test
public void buildFiveRandomStrings() {
    for (int q = 0; q < 5; q++) {
        System.out.println(randomString(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")); // The character set can basically be anything
    }
}

但另一方面,您也可以使用具有相当好的熵的UUID :

UUID.randomUUID().toString().replace("-", "")
于 2018-02-21T15:29:56.683 回答
8

我正在使用Apache Commons的库来生成字母数字字符串:

import org.apache.commons.lang3.RandomStringUtils;

String keyLength = 20;
RandomStringUtils.randomAlphanumeric(keylength);

它又快又简单!

于 2020-04-11T04:37:05.470 回答
7
import java.util.*;
import javax.swing.*;

public class alphanumeric {
    public static void main(String args[]) {
        String nval, lenval;
        int n, len;

        nval = JOptionPane.showInputDialog("Enter number of codes you require: ");
        n = Integer.parseInt(nval);

        lenval = JOptionPane.showInputDialog("Enter code length you require: ");
        len = Integer.parseInt(lenval);

        find(n, len);
    }

    public static void find(int n, int length) {
        String str1 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        StringBuilder sb = new StringBuilder(length);
        Random r = new Random();

        System.out.println("\n\t Unique codes are \n\n");
        for(int i=0; i<n; i++) {
            for(int j=0; j<length; j++) {
                sb.append(str1.charAt(r.nextInt(str1.length())));
            }
            System.out.println("  " + sb.toString());
            sb.delete(0, length);
        }
    }
}
于 2011-06-30T05:34:20.277 回答
7

您提到“简单”,但以防万一其他人正在寻找满足更严格安全要求的东西,您可能想看看jpwgen。jpwgen 是仿照Unix 中的pwgen建模的,并且是非常可配置的。

于 2011-09-09T21:23:10.587 回答
5

如果您的密码必须包含数字和字母特殊字符,您可以使用以下代码:

private static final String NUMBERS = "0123456789";
private static final String UPPER_ALPHABETS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String LOWER_ALPHABETS = "abcdefghijklmnopqrstuvwxyz";
private static final String SPECIALCHARACTERS = "@#$%&*";
private static final int MINLENGTHOFPASSWORD = 8;

public static String getRandomPassword() {
    StringBuilder password = new StringBuilder();
    int j = 0;
    for (int i = 0; i < MINLENGTHOFPASSWORD; i++) {
        password.append(getRandomPasswordCharacters(j));
        j++;
        if (j == 3) {
            j = 0;
        }
    }
    return password.toString();
}

private static String getRandomPasswordCharacters(int pos) {
    Random randomNum = new Random();
    StringBuilder randomChar = new StringBuilder();
    switch (pos) {
        case 0:
            randomChar.append(NUMBERS.charAt(randomNum.nextInt(NUMBERS.length() - 1)));
            break;
        case 1:
            randomChar.append(UPPER_ALPHABETS.charAt(randomNum.nextInt(UPPER_ALPHABETS.length() - 1)));
            break;
        case 2:
            randomChar.append(SPECIALCHARACTERS.charAt(randomNum.nextInt(SPECIALCHARACTERS.length() - 1)));
            break;
        case 3:
            randomChar.append(LOWER_ALPHABETS.charAt(randomNum.nextInt(LOWER_ALPHABETS.length() - 1)));
            break;
    }
    return randomChar.toString();
}
于 2012-11-01T05:43:49.960 回答
5

您可以使用 UUID 类及其 getLeastSignificantBits() 消息来获取 64 位随机数据​​,然后将其转换为 radix 36 数字(即由 0-9,AZ 组成的字符串):

Long.toString(Math.abs( UUID.randomUUID().getLeastSignificantBits(), 36));

这会产生一个最长为 13 个字符的字符串。我们使用 Math.abs() 来确保没有减号潜入。

于 2013-07-29T14:07:23.630 回答
5

这是AbacusUtil的单行代码:

String.valueOf(CharStream.random('0', 'z').filter(c -> N.isLetterOrDigit(c)).limit(12).toArray())

随机并不意味着它必须是唯一的。要获取唯一字符串,请使用:

N.uuid() // E.g.: "e812e749-cf4c-4959-8ee1-57829a69a80f". length is 36.
N.guid() // E.g.: "0678ce04e18945559ba82ddeccaabfcd". length is 32 without '-'
于 2016-11-28T20:25:45.950 回答
4

这是一个 Scala 解决方案:

(for (i <- 0 until rnd.nextInt(64)) yield { 
  ('0' + rnd.nextInt(64)).asInstanceOf[Char] 
}) mkString("")
于 2012-07-24T11:11:01.980 回答
4

使用Apache Commons库,它可以在一行中完成:

import org.apache.commons.lang.RandomStringUtils;
RandomStringUtils.randomAlphanumeric(64);

文档

于 2012-10-15T07:52:12.753 回答
4
public static String randomSeriesForThreeCharacter() {
    Random r = new Random();
    String value = "";
    char random_Char ;
    for(int i=0; i<10; i++)
    {
        random_Char = (char) (48 + r.nextInt(74));
        value = value + random_char;
    }
    return value;
}
于 2012-12-24T12:41:23.277 回答
4

我认为这是这里最小的解决方案,或者几乎是最小的解决方案之一:

 public String generateRandomString(int length) {
    String randomString = "";

    final char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890".toCharArray();
    final Random random = new Random();
    for (int i = 0; i < length; i++) {
        randomString = randomString + chars[random.nextInt(chars.length)];
    }

    return randomString;
}

代码工作得很好。如果您使用这种方法,我建议您使用 10 个以上的字符。碰撞发生在 5 个字符/30362 次迭代。这花了9秒。

于 2018-11-26T18:31:13.923 回答
3
public static String getRandomString(int length)
{
    String randomStr = UUID.randomUUID().toString();
    while(randomStr.length() < length) {
        randomStr += UUID.randomUUID().toString();
    }
    return randomStr.substring(0, length);
}
于 2012-12-03T06:40:44.383 回答
2
public static String getRandomString(int length) {
    char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST".toCharArray();

    StringBuilder sb = new StringBuilder();
    Random random = new Random();
    for (int i = 0; i < length; i++) {
        char c = chars[random.nextInt(chars.length)];
        sb.append(c);
    }
    String randomStr = sb.toString();

    return randomStr;
}
于 2018-08-17T13:05:11.540 回答
2
public class Utils {
    private final Random RANDOM = new SecureRandom();
    private final String ALPHABET = "0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm";

    private String generateRandomString(int length) {
        StringBuffer buffer = new StringBuffer(length);
        for (int i = 0; i < length; i++) {
            buffer.append(ALPHABET.charAt(RANDOM.nextInt(ALPHABET.length())));
        }
        return new String(buffer);
    } 
}
于 2021-04-09T11:18:33.243 回答
1

最佳随机字符串生成器方法

public class RandomStringGenerator{

    private static int randomStringLength = 25 ;
    private static boolean allowSpecialCharacters = true ;
    private static String specialCharacters = "!@$%*-_+:";
    private static boolean allowDuplicates = false ;

    private static boolean isAlphanum = false;
    private static boolean isNumeric = false;
    private static boolean isAlpha = false;
    private static final String alphabet = "abcdefghijklmnopqrstuvwxyz";
    private static boolean mixCase = false;
    private static final String capAlpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final String num = "0123456789";

    public static String getRandomString() {
        String returnVal = "";
        int specialCharactersCount = 0;
        int maxspecialCharacters = randomStringLength/4;

        try {
            StringBuffer values = buildList();
            for (int inx = 0; inx < randomStringLength; inx++) {
                int selChar = (int) (Math.random() * (values.length() - 1));
                if (allowSpecialCharacters)
                {
                    if (specialCharacters.indexOf("" + values.charAt(selChar)) > -1)
                    {
                        specialCharactersCount ++;
                        if (specialCharactersCount > maxspecialCharacters)
                        {
                            while (specialCharacters.indexOf("" + values.charAt(selChar)) != -1)
                            {
                                selChar = (int) (Math.random() * (values.length() - 1));
                            }
                        }
                    }
                }
                returnVal += values.charAt(selChar);
                if (!allowDuplicates) {
                    values.deleteCharAt(selChar);
                }
            }
        } catch (Exception e) {
            returnVal = "Error While Processing Values";
        }
        return returnVal;
    }

    private static StringBuffer buildList() {
        StringBuffer list = new StringBuffer(0);
        if (isNumeric || isAlphanum) {
            list.append(num);
        }
        if (isAlpha || isAlphanum) {
            list.append(alphabet);
            if (mixCase) {
                list.append(capAlpha);
            }
        }
        if (allowSpecialCharacters)
        {
            list.append(specialCharacters);
        }
        int currLen = list.length();
        String returnVal = "";
        for (int inx = 0; inx < currLen; inx++) {
            int selChar = (int) (Math.random() * (list.length() - 1));
            returnVal += list.charAt(selChar);
            list.deleteCharAt(selChar);
        }
        list = new StringBuffer(returnVal);
        return list;
    }   

}
于 2012-04-28T07:27:28.423 回答
1

在以前的答案中有很多使用 StringBuilder 。我想这很容易,但它需要每个字符调用一个函数,增加一个数组等......

如果使用字符串生成器,建议指定字符串所需的容量,即

new StringBuilder(int capacity);

这是一个不使用 StringBuilder 或 String 附加的版本,也没有字典。

public static String randomString(int length)
{
    SecureRandom random = new SecureRandom();
    char[] chars = new char[length];
    for(int i=0; i<chars.length; i++)
    {
        int v = random.nextInt(10 + 26 + 26);
        char c;
        if (v < 10)
        {
            c = (char)('0' + v);
        }
        else if (v < 36)
        {
            c = (char)('a' - 10 + v);
        }
        else
        {
            c = (char)('A' - 36 + v);
        }
        chars[i] = c;
    }
    return new String(chars);
}
于 2012-12-03T15:16:17.480 回答
1

您可以创建一个包含所有字母和数字的字符数组,然后您可以从该字符数组中随机选择并创建您自己的字符串密码。

char[] chars = new char[62]; // Sum of letters and numbers

int i = 0;

for(char c = 'a'; c <= 'z'; c++) { // For letters
    chars[i++] = c;
}

for(char c = '0'; c <= '9';c++) { // For numbers
    chars[i++] = c;
}

for(char c = 'A'; c <= 'Z';c++) { // For capital letters
    chars[i++] = c;
}

int numberOfCodes = 0;
String code = "";
while (numberOfCodes < 1) { // Enter how much you want to generate at one time
    int numChars = 8; // Enter how many digits you want in your password

    for(i = 0; i < numChars; i++) {
        char c = chars[(int)(Math.random() * chars.length)];
        code = code + c;
    }
    System.out.println("Code is:" + code);
}
于 2013-01-09T16:04:22.143 回答
1

也许这有帮助

package password.generater;

import java.util.Random;

/**
 *
 * @author dell
 */
public class PasswordGenerater {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        int length= 11;
        System.out.println(generatePswd(length));

        // TODO code application logic here
    }
    static char[] generatePswd(int len){
        System.out.println("Your Password ");
        String charsCaps="ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
        String Chars="abcdefghijklmnopqrstuvwxyz";
        String nums="0123456789";
        String symbols="!@#$%^&*()_+-=.,/';:?><~*/-+";
        String passSymbols=charsCaps + Chars + nums +symbols;
        Random rnd=new Random();
        char[] password=new char[len];

        for(int i=0; i<len;i++){
            password[i]=passSymbols.charAt(rnd.nextInt(passSymbols.length()));
        }
      return password;

    }
}
于 2016-08-04T20:28:17.790 回答
0

我开发了一个应用程序来为我的项目开发一个自动生成的字母数字字符串。在这个字符串中,前三个字符是按字母顺序排列的,接下来的七个是整数。

public class AlphaNumericGenerator {

    public static void main(String[] args) {
        java.util.Random r = new java.util.Random();
        int i = 1, n = 0;
        char c;
        String str = "";
        for (int t = 0; t < 3; t++) {
            while (true) {
                i = r.nextInt(10);
                if (i > 5 && i < 10) {

                    if (i == 9) {
                        i = 90;
                        n = 90;
                        break;
                    }
                    if (i != 90) {
                        n = i * 10 + r.nextInt(10);
                        while (n < 65) {
                            n = i * 10 + r.nextInt(10);
                        }
                    }
                    break;
                }
            }
            c = (char)n;

            str = String.valueOf(c) + str;
        }

        while(true){
            i = r.nextInt(10000000);
            if(i > 999999)
                break;
        }
        str = str + i;
        System.out.println(str);
    }
}
于 2009-06-19T08:36:46.420 回答
0

这是一个使用 UUID 作为字符库并且能够(几乎)指定任何长度的简单单行代码。(是的,我知道之前有人建议使用 UUID。)

public static String randString(int length) {
    return UUID.randomUUID().toString().replace("-", "").substring(0, Math.min(length, 32)) + (length > 32 ? randString(length - 32) : "");
}
于 2018-03-01T19:01:33.880 回答
0

这是一个基于流的 Java 8 解决方案。

    public String generateString(String alphabet, int length) {
        return generateString(alphabet, length, new SecureRandom()::nextInt);
    }

    // nextInt = bound -> n in [0, bound)
    public String generateString(String source, int length, IntFunction<Integer> nextInt) {
        StringBuilder sb = new StringBuilder();
        IntStream.generate(source::length)
                .boxed()
                .limit(length)
                .map(nextInt::apply)
                .map(source::charAt)
                .forEach(sb::append);

        return sb.toString();
    }

像这样使用它

String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int length = 12;
String generated = generateString(alphabet, length);
System.out.println(generated);

该函数nextInt应该接受一个 int并返回一个介于和bound之间的随机数。0bound - 1

于 2019-02-27T13:52:23.043 回答
0
public static String RandomAlphanum(int length)
{
    String charstring = "abcdefghijklmnopqrstuvwxyz0123456789";
    String randalphanum = "";
    double randroll;
    String randchar;
    for (double i = 0; i < length; i++)
    {
        randroll = Math.random();
        randchar = "";
        for (int j = 1; j <= 35; j++)
        {
            if (randroll <= (1.0 / 36.0 * j))
            {
                randchar = Character.toString(charstring.charAt(j - 1));
                break;
            }
        }
        randalphanum += randchar;
    }
    return randalphanum;
}

我使用了一个非常原始的算法,使用 Math.random()。要增加随机性,您可以直接实现util.Date该类。尽管如此,它仍然有效。

于 2019-12-07T06:23:33.683 回答
-1

还有一个解决方案...

public static String generatePassword(int passwordLength) {
    int asciiFirst = 33;
    int asciiLast = 126;
    Integer[] exceptions = { 34, 39, 96 };

    List<Integer> exceptionsList = Arrays.asList(exceptions);
    SecureRandom random = new SecureRandom();
    StringBuilder builder = new StringBuilder();
    for (int i=0; i<passwordLength; i++) {
        int charIndex;

        do {
            charIndex = random.nextInt(asciiLast - asciiFirst + 1) + asciiFirst;
        }
        while (exceptionsList.contains(charIndex));

        builder.append((char) charIndex);
    }
    return builder.toString();
}
于 2014-12-08T01:41:10.750 回答
-1

此外,您可以通过 ASCII 表中的数据生成任何小写或大写字母甚至特殊字符。例如,生成从 A (DEC 65) 到 Z (DEC 90) 的大写字母:

String generateRandomStr(int min, int max, int size) {
    String result = "";
    for (int i = 0; i < size; i++) {
        result += String.valueOf((char)(new Random().nextInt((max - min) + 1) + min));
    }
    return result;
}

生成的输出generateRandomStr(65, 90, 100));

TVLPFQJCYFXQDCQSLKUKKILKKHAUFYEXLUQFHDWNMRBIRRRWNXNNZQTINZPCTKLHGHVYWRKEOYNSOFPZBGEECFMCOKWHLHCEWLDZ
于 2017-07-01T23:52:57.547 回答
-1

高效而短暂。

/**
 * Utility class for generating random Strings.
 */
public interface RandomUtil {

    int    DEF_COUNT = 20;
    Random RANDOM    = new SecureRandom();

    /**
     * Generate a password.
     *
     * @return the generated password
     */
    static String generatePassword() {
        return generate(true, true);
    }

    /**
     * Generate an activation key.
     *
     * @return the generated activation key
     */
    static String generateActivationKey() {
        return generate(false, true);
    }

    /**
     * Generate a reset key.
     *
     * @return the generated reset key
     */
    static String generateResetKey() {
        return generate(false, true);
    }

    static String generate(boolean letters, boolean numbers) {
        int
            start = ' ',
            end   = 'z' + 1,
            count = DEF_COUNT,
            gap   = end - start;
        StringBuilder builder = new StringBuilder(count);

        while (count-- != 0) {
            int codePoint = RANDOM.nextInt(gap) + start;

            switch (getType(codePoint)) {
                case UNASSIGNED:
                case PRIVATE_USE:
                case SURROGATE:
                    count++;
                    continue;
            }

            int numberOfChars = charCount(codePoint);

            if (count == 0 && numberOfChars > 1) {
                count++;
                continue;
            }

            if (letters && isLetter(codePoint)
                || numbers && isDigit(codePoint)
                || !letters && !numbers) {

                builder.appendCodePoint(codePoint);
                if (numberOfChars == 2)
                    count--;
            }
            else
                count++;
        }
        return builder.toString();
    }
}
于 2019-03-27T12:14:17.683 回答
-1

我正在使用一个使用 Java 8 的非常简单的解决方案。只需根据您的需要对其进行自定义即可。

...
import java.security.SecureRandom;
...

//Generate a random String of length between 10 to 20.
//Length is also randomly generated here.
SecureRandom random = new SecureRandom();

String sampleSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";

int stringLength = random.ints(1, 10, 21).mapToObj(x -> x).reduce((a, b) -> a).get();

String randomString = random.ints(stringLength, 0, sampleSet.length() - 1)
        .mapToObj(x -> sampleSet.charAt(x))
        .collect(Collector
            .of(StringBuilder::new, StringBuilder::append,
                StringBuilder::append, StringBuilder::toString));

我们可以使用它来生成一个像这样的字母数字随机字符串(返回的字符串将强制包含一些非数字字符以及一些数字字符):

public String generateRandomString() {
            
    String sampleSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_";
    String sampleSetNumeric = "0123456789";
    
    String randomString = getRandomString(sampleSet, 10, 21);
    String randomStringNumeric = getRandomString(sampleSetNumeric, 10, 21);
    
    randomString = randomString + randomStringNumeric;
    
    //Convert String to List<Character>
    List<Character> list = randomString.chars()
            .mapToObj(x -> (char)x)
            .collect(Collectors.toList());
    
    Collections.shuffle(list);
    
    //This is needed to force a non-numeric character as the first String
    //Skip this for() if you don't need this logic

    for(;;) {
        if(Character.isDigit(list.get(0))) Collections.shuffle(list);
        else break;
    }
    
    //Convert List<Character> to String
    randomString = list.stream()
            .map(String::valueOf)
            .collect(Collectors.joining());
    
    return randomString;
    
}

//Generate a random number between the lower bound (inclusive) and upper bound (exclusive)
private int getRandomLength(int min, int max) {
    SecureRandom random = new SecureRandom();
    return random.ints(1, min, max).mapToObj(x -> x).reduce((a, b) -> a).get();
}

//Generate a random String from the given sample string, having a random length between the lower bound (inclusive) and upper bound (exclusive)
private String getRandomString(String sampleSet, int min, int max) {
    SecureRandom random = new SecureRandom();
    return random.ints(getRandomLength(min, max), 0, sampleSet.length() - 1)
    .mapToObj(x -> sampleSet.charAt(x))
    .collect(Collector
        .of(StringBuilder::new, StringBuilder::append,
            StringBuilder::append, StringBuilder::toString));
}
于 2021-04-08T19:37:37.213 回答