我使用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位具有相同的结果。
答案 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());
}
}
}
}