java - number - randomstringutils




如何生成一个随机的字母数字字符串? (20)

算法

要生成一个随机字符串,将从可接受符号集合中随机抽取的字符连接起来,直到字符串达到所需的长度。

履行

这里有一些相当简单和非常灵活的代码来生成随机标识符。 阅读重要应用笔记后面的信息

import java.security.SecureRandom;
import java.util.Locale;
import java.util.Objects;
import java.util.Random;

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占用大量空间:只有122位熵的36个字符。 (并非随机选择“随机”UUID的所有位)随机选择的字母数字字符串仅包含21个字符的熵。

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

我一直在寻找一种简单的 Java算法来生成一个伪随机字母数字字符串。 在我的情况下,它将被用作一个独特的会话/密钥标识符,“很可能”在500K +一代中是唯一的(我的需求并不需要任何更复杂的东西)。 理想情况下,我可以根据我的独特需要指定长度。 例如,生成的长度为12的字符串可能看起来像"AEYGF7K0DM1X"


  1. 按照您的要求更改字符串字符。

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


public static String getRandomString(int length) {
       final String characters = "[email protected]#$%^&*()_+";
       StringBuilder result = new StringBuilder();
       while(length > 0) {
           Random rand = new Random();
           result.append(characters.charAt(rand.nextInt(characters.length())));
           length--;
       }
       return result.toString();
    }

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

Best Random String Generator Method

public class RandomStringGenerator{

    private static int randomStringLength = 25 ;
    private static boolean allowSpecialCharacters = true ;
    private static String specialCharacters = "[email protected]$%*-_+:";
    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;
    }   

}

Here is the one line code by AbacusUtil

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

Random doesn't mean it must be unique. to get unique strings, using:

N.uuid() // e.g.: "e812e749-cf4c-4959-8ee1-57829a69a80f". length is 36.
N.guid() // e.g.: "0678ce04e18945559ba82ddeccaabfcd". length is 32 without '-'

Here it is a Scala solution:

(for (i <- 0 until rnd.nextInt(64)) yield { 
  ('0' + rnd.nextInt(64)).asInstanceOf[Char] 
}) mkString("")

You can use following code , if your password mandatory contains numbers alphabetic special characters:

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

}

You can use the UUID class with its getLeastSignificantBits() message to get 64bit of Random data, then convert it to a radix 36 number (ie a string consisting of 0-9,AZ):

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

This yields a String up to 13 characters long. We use Math.abs() to make sure there isn't a minus sign sneaking in.



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

import java.util.UUID

UUID.randomUUID().toString();

简单。

这样做的好处是UUID非常好,而且保证几乎不可能发生碰撞。

维基百科有一个很好的解释:

“......只有在接下来的100年内每秒产生10亿个UUID之后,创建一个副本的可能性将大约为50%。”

http://en.wikipedia.org/wiki/Universally_unique_identifier#Random_UUID_probability_of_duplicates

前4位是版本类型,2是变体,因此您可以获得122位随机数。 所以如果你想要从最后截断来减少UUID的大小。 这不是推荐的,但你仍然有大量的随机性,足以让你的500k记录变得容易。


使用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提供了一个构造函数来生成一个随机数,均匀分布在0 to (2^numBits - 1)的范围内。 不幸的是35没有可以通过2 ^ numBits - 1接收的数字。所以我们有两个选择:或者用2^5-1=31或者2^6-1=63 。 如果我们选择2^6我们会得到很多“不必要的”/“更长的”数字。 因此2^5是更好的选择,即使我们松动4个字符(wz)。 现在要生成一定长度的字符串,我们可以简单地使用2^(length*numBits)-1数字。 最后一个问题是,如果我们想要一个具有一定长度的字符串,随机可以生成一个小数字,所以长度不符合,所以我们必须将字符串填充到它所需的长度前置零。



它在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

您可以为此使用Apache库: RandomStringUtils

RandomStringUtils.randomAlphanumeric(20).toUpperCase();

没有任何外部库,这很容易实现。

1.加密伪随机数据生成

首先你需要一个加密PRNG。 Java的SecureRandom通常使用机器上最好的熵源(例如/dev/random )。 在这里阅读更多。

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

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

2.可能值的必需空间

接下来,你必须决定你的代币需要的“独特性”。 考虑熵的唯一要点是确保系统能抵抗暴力攻击:可能值的空间必须非常大,以至于任何攻击者只能在非滑稽时间1尝试微不足道的比例值1 。 唯一标识符如随机UUID具有122bit的熵(即2 ^ 122 = 5.3x10 ^ 36) - 碰撞的机会是“*(...)”,因为十亿分之一的重复机率为103万亿版本4 UUID必须生成2 “。 我们将选择128位,因为它恰好适合于16个字节,并且对于基本上每一个都是独一无二的,但却是最极端的用例,您不必考虑重复。 这里是一个简单的熵比较表,包括生日问题的简单分析。

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

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

3.二进制文本编码

典型的编码包括:

  • Base64每个字符编码6bit,产生33%的开销。 不幸的是,在JDK中没有标准的实现(在Android )。 但是有大量的图书馆增加了这一点。 缺点是, Base64对于例如。 在大多数需要额外编码的文件系统(例如url编码 )中作为文件名。 用padding编码16个字节的示例: XfJhfv3C0P6ag7y9VQxSbw==

  • Base32每个字符编码5bit,产生40%的开销。 这将使用AZ2-7 ,这使得空间效率合理,而不区分大小写的字母数字。 和Base64一样, JDK中没有标准的实现 。 编码16个字节而没有填充的示例: WUPIL5DQTZGMF4D3NX5L7LNFOY

  • Base16 (十六进制)每个字符编码4位,每个字节需要2个字符(即16个字节创建一个长度为32的字符串)。 因此,十六进制的空间效率低于Base32但在大多数情况下(url)可以安全使用,因为它只使用0-9AF 编码16个字节的示例: 4fa3dd0f57cb3bf331441ed285b27735请参阅关于转换为十六进制的SO讨论。

Base85和异国情调的Base122等其他编码存在更好/更差的空间效率。 你可以创建自己的编码(基本上这个线程中的大多数答案都可以),但如果你没有特别的要求,我会建议你不要这样做。 请参阅Wikipedia文章中的更多编码方案。

4.总结和例子

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

  • ...使用家庭brew编码: 如果他们看到您使用的是什么标准编码,而不是奇怪的一次创建字符,那么对其他人更好的可维护性和可读性。
  • ...使用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); //hex encoding
}

//generateRandomHexToken(16) -> 2189df7475e96aa3982dbeab266497cd

示例:工具

如果你想要一个随时可用的cli工具,你可以使用骰子: https://github.com/patrickfav/dicehttps://github.com/patrickfav/dice


简单而简单的解决方案,但只使用小写和数字:

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

这个尺寸大约是12位数字,以36为基数,并且不能进一步改进。 当然你可以附加多个实例。


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

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

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

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




alphanumeric