使用StringBuilder生成随机字符串会导致长度小于预定义长度的字符串

时间:2014-12-01 07:37:23

标签: java

我使用for循环和StringBuilder生成一些具有指定长度的随机字符串,但是我得到的字符串短于指定的长度。我的问题是,为什么有些字符串生成的长度正确,有些不是?

public class PasswordGen {

    public static void main(final String[] args) {
        final String[] chars = characters.split("");
        final List<String> characterList = Arrays.asList(chars);
        final Random rng = new SecureRandom();
        Collections.shuffle(characterList, rng);
        final int passwordsToGenerate = 16;
        final int length = 31;
        for (int i = 0; i < passwordsToGenerate; i++) {
            final StringBuilder builder = new StringBuilder();
            for (int j = 0; j < length; j++) {
                final int index = rng.nextInt(characterList.size());
                builder.append(characterList.get(index));
            }
            final String password = builder.toString();
            System.out.println(password);
            if (password.length() < 31) {
                System.out.println("^ is not 31 characters in length: " + password.length());
            }
        }

    }

    public static final String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
}

输出:

LMUYN7bHKX13Rx1dwEkbHI8KjUONbDN
hnwMBD2LPHyuoYffGy7eC5STAg8heB
^ is not 31 characters in length: 30
EbburpyvZqc71mPadP8rYc6cJ8K9wl
^ is not 31 characters in length: 30
nLb58OzfnERsPm1SdR1nKBuOilhXzG
^ is not 31 characters in length: 30
c44M4Pk1kDIBMVqL0o5NybPA5t8zI3D
I3ttG7TvO8pKOp9yb5mGzJtnkTNVLH9
K1md1ORt2W3s8iR3RpMf2yNHjMrH8N
^ is not 31 characters in length: 30
G8daUMVLoMqpYqSrAUzSdI5IJCM7GSM
KMfaLvfCaudpRACpuOlA1gO3rqmhBs
^ is not 31 characters in length: 30
Y20V5RcKUiS8Ny9NpARmTMac29y8Z
^ is not 31 characters in length: 29
Rse101oxhOMXRdpchp4X3Uzm00Gzsc
^ is not 31 characters in length: 30
oQxaYE9qx1cEJP8KvTGdwo1IJhNH41O
y6E2WrKEAl2zWV6BCkH1JaWvz3aBxvs
QFautBHKlgDPlJhmge7n6Kf79G6mfu
^ is not 31 characters in length: 30
l2OBC9sFsZOfB481HXLsIiIwnmcOpdB
A4CTQj9Xc7grxtYYFzDRLelf3YQOTWV

我尝试在内部for循环内,在获取下一个索引之前和之后,在将字符附加到构建器之前和之后,在设置密码变量之前和之后以及之前和之后添加Thread.sleep()块内部循环,看它是否与线程有某种关系。结果没有明显差异。

我使用的是Windows 7 Professional 64位,并使用JDK 7u67和8u11进行了测试,32位和64位具有相同的结果。

5 个答案:

答案 0 :(得分:3)

不要用空字符串拆分字符,只需使用getChars方法。在不同版本的java中,由空字符串行为拆分不一样。例如:Java split string on empty delimiter returns empty string at the beginning?

答案 1 :(得分:2)

问题是由于characters.split("");,它将返回一个数组,其中第一个条目是Java版本7及之前的空字符串。它将return the expected result for Java 8 and up

您可以使用characters.split("(?!^)"); to split a string into characters。此方法适用于每个Java版本。 split()函数需要一个正则表达式,并且上面的正则表达式在字符串的开头不匹配,而在其他地方匹配时,这避免产生一个空字符串作为第一个条目。

或者作为更清洁的替代方案,使用String.toCharArray()获取所有字符的数组。

答案 2 :(得分:1)

split()来电中,空正则表达式匹配characters的开头和结尾。这导致""中的两个characterList条目。无论什么时候他们被选中,你最终都会产生短暂的输出。

答案 3 :(得分:0)

试试这段代码:

static final String AlphaNumeric = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static Random rnd = new Random();


public static String randomString (int len){
     StringBuilder sb = new StringBuilder(len);
     for( int i = 0; i < len; i++ )
        sb.append( AlphaNumeric.charAt( rnd.nextInt(AlphaNumeric.length()) ) );
        return sb.toString();
}

您可以将其他wild card character or small cases添加到AlphaNumeric以生成更复杂或唯一的令牌。

调用功能&amp;无论长度如何,都会为你生成随机字符串。

Here's 一个正在运行的例子。

答案 4 :(得分:0)

你的问题在于使用split(),它也会在String []中添加空字符串,你可以通过检查chars.length(63)来轻松检查。

以下代码必须符合您的要求:

public class PasswordGen {

public static final String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

public static void main(final String[] args) {
    final int characterListSize = characters.length();
    char[] arr = characters.toCharArray();
    List<Character> characterList = new ArrayList<Character>();
    for (char c : arr)
        characterList.add(c);

    // System.out.println(characterList);
    final Random rng = new SecureRandom();
    Collections.shuffle(characterList, rng);
    final int passwordsToGenerate = 16;
    final int length = 31;
    for (int i = 0; i < passwordsToGenerate; i++) {
        final StringBuilder builder = new StringBuilder();
        for (int j = 0; j < length; j++) {
            int index = rng.nextInt(characterListSize);
            builder.append(characters.charAt(index));
        }
        final String password = builder.toString();
        if (password.length() < 31) {
            System.out.println("^ is not 31 characters in length: "
                    + password.length());
        }
    }

}

}