如何生成随机的字母数字字符串

1968

我一直在寻找一个简单的Java算法来生成伪随机的字母数字字符串。在我的情况下,它将被用作唯一的会话/键标识符,可能在500K+次生成中是唯一的(我的需求并不需要更复杂的东西)。

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


165
注意生日悖论。 - pablosaraiva
63
即使考虑到生日悖论,如果您使用12个字母数字字符(共62个字符),仍需要超过340亿个字符串才能达到悖论。而且,生日悖论并不保证一定会发生冲突,它只是表示有超过50%的概率。 - NullUserException
6
@NullUserException:每次尝试的成功率达到50%真是太高了,即使尝试10次,成功率也达到0.999。考虑到你可以在24小时内尝试很多次,因此你不需要340亿个字符串就足以确信至少猜中其中一个。这就是为什么某些会话令牌应该非常非常长的原因。 - Pijusn
20
我认为这3个单行代码非常有用。Long.toHexString(Double.doubleToLongBits(Math.random())); 生成一个16进制的随机字符串。UUID.randomUUID().toString(); 生成一个随机唯一标识符。RandomStringUtils.randomAlphanumeric(12); 生成一个包含12个字符的随机字母数字组合。 - Manindar
25
我知道这已经是老话题了,但是,在生日悖论中,“50%的机率”不是“每一次尝试”,而是“存在至少一对重复的机率为50%,在(这种情况下)340亿个字符串中”。你需要拥有1.6*10^21-1.6e21个条目,才能每次尝试有50%的机会。 - Tin Wizard
显示剩余3条评论
46个回答

2
public static String getRandomString(int length)
{
    String randomStr = UUID.randomUUID().toString();
    while(randomStr.length() < length) {
        randomStr += UUID.randomUUID().toString();
    }
    return randomStr.substring(0, length);
}

4
这基本上与两年前 Steve McLeod 的答案 相同。 - erickson

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;
}

1
非常好!但是在for循环中应该使用length而不是chars.lengthfor (int i = 0; i < length; i++) - Incinerator

1

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

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

new StringBuilder(int capacity);

这里有一个版本,它不使用 StringBuilder 或字符串拼接,也没有使用字典。
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);
}

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;
    }   

}

需要解释一下。 - Peter Mortensen

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;

    }
}

这个答案对已经给出的其他答案有什么补充? - erickson

1

你可以在一行代码中实现,无需使用外部库。

int length = 12;
String randomString = new Random().ints(48, 122).filter(i -> (i < 58 || i > 64) && (i < 91 || i > 96)).limit(length).collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString();
System.out.print(randomString);

我已将长度分离为一个参数,并添加了一行代码来打印结果。

这段代码创建了一个随机整数流,范围限定在字母数字ASCII范围内。然后它过滤掉一些符号,因为字母数字范围不是连续的。然后它限制了长度并将结果收集到一个字符串中。

由于这种方法会丢弃大约20%的生成的数字/字符(因为它们是符号),所以会有一些性能影响。

我觉得它不太易读,但我认为没有人提出过一个本地的Java解决方案只用一行代码。


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);
}

2
似乎在很大程度上重复了我的答案,而我的答案是在两年前给出的。 - erickson

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) : "");
}

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应该接受一个整数bound,并返回一个介于0bound - 1之间的随机数。

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);
    }
}

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