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

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个回答

0

给定一些字符(AllCharacters),您可以随机选择字符串中的一个字符。然后使用for循环重复获取随机字符。

public class MyProgram {
  static String getRandomString(int size) {
      String AllCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
      StringBuilder sb = new StringBuilder(size);
      int length = AllCharacters.length();
      for (int i = 0; i < size; i++) {
          sb.append(AllCharacters.charAt((int)(length * Math.random())));
      }
      return sb.toString();
  }

  public static void main(String[] args) {
      System.out.println(MyProgram.getRandomString(30));
  }
}

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 类。尽管如此,它仍然有效。


-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

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

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

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

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