我一直在寻找一种简单的Java算法来生成伪随机字母数字字符串。在我的情况下,它将被用作唯一的会话/密钥标识符,“很可能”在超过50万代的时间内是唯一的(我的需求实际上不需要更复杂的东西)。
理想情况下,我可以根据我的独特性需求指定长度。例如,生成的长度为12的字符串可能看起来像“AEYGF7K0DM1X”。
我一直在寻找一种简单的Java算法来生成伪随机字母数字字符串。在我的情况下,它将被用作唯一的会话/密钥标识符,“很可能”在超过50万代的时间内是唯一的(我的需求实际上不需要更复杂的东西)。
理想情况下,我可以根据我的独特性需求指定长度。例如,生成的长度为12的字符串可能看起来像“AEYGF7K0DM1X”。
当前回答
根据您的要求更改字符串字符。字符串是不可变的。这里StringBuilder.append比字符串串联更有效。
public static String getRandomString(int length) {
final String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_+";
StringBuilder result = new StringBuilder();
while(length > 0) {
Random rand = new Random();
result.append(characters.charAt(rand.nextInt(characters.length())));
length--;
}
return result.toString();
}
其他回答
在前面的答案中有很多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);
}
使用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');
}
}
为什么选择长度*5?让我们假设一个长度为1的随机字符串的简单情况,即一个随机字符。要获得包含所有数字0-9和字符a-z的随机字符,我们需要一个介于0和35之间的随机数来获得每个字符中的一个。
BigInteger提供了一个构造函数来生成一个随机数,均匀分布在0到(2^numBits-1)的范围内。不幸的是,35不是一个可以由2^numBits-1接收的数字。
所以我们有两个选择:要么选择2^5-1=31,要么选择2^ 6-1=63。如果我们选择2^6,我们会得到很多“不必要”/“更长”的数字。因此,2^5是更好的选择,即使我们丢失了四个字符(w-z)。现在要生成特定长度的字符串,我们可以简单地使用2^(length*numBits)-1数字。最后一个问题是,如果我们想要一个具有一定长度的字符串,随机可能会生成一个小数字,因此长度不符合要求,因此我们必须将字符串填充到所需的长度,并加上前缀零。
public static String randomSeriesForThreeCharacter() {
Random r = new Random();
String value = "";
char random_Char ;
for(int i=0; i<10; i++)
{
random_Char = (char) (48 + r.nextInt(74));
value = value + random_char;
}
return value;
}
我认为这是这里最小的解决方案,或者几乎是最小的方案之一:
public String generateRandomString(int length) {
String randomString = "";
final char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890".toCharArray();
final Random random = new Random();
for (int i = 0; i < length; i++) {
randomString = randomString + chars[random.nextInt(chars.length)];
}
return randomString;
}
代码工作正常。如果您正在使用此方法,我建议您使用超过10个字符。在5个字符/30362次迭代时发生冲突。这花了9秒。
我找到了生成随机十六进制编码字符串的解决方案。所提供的单元测试似乎符合我的主要用例。虽然,它比提供的一些其他答案稍微复杂一些。
/**
* Generate a random hex encoded string token of the specified length
*
* @param length
* @return random hex string
*/
public static synchronized String generateUniqueToken(Integer length){
byte random[] = new byte[length];
Random randomGenerator = new Random();
StringBuffer buffer = new StringBuffer();
randomGenerator.nextBytes(random);
for (int j = 0; j < random.length; j++) {
byte b1 = (byte) ((random[j] & 0xf0) >> 4);
byte b2 = (byte) (random[j] & 0x0f);
if (b1 < 10)
buffer.append((char) ('0' + b1));
else
buffer.append((char) ('A' + (b1 - 10)));
if (b2 < 10)
buffer.append((char) ('0' + b2));
else
buffer.append((char) ('A' + (b2 - 10)));
}
return (buffer.toString());
}
@Test
public void testGenerateUniqueToken(){
Set set = new HashSet();
String token = null;
int size = 16;
/* Seems like we should be able to generate 500K tokens
* without a duplicate
*/
for (int i=0; i<500000; i++){
token = Utility.generateUniqueToken(size);
if (token.length() != size * 2){
fail("Incorrect length");
} else if (set.contains(token)) {
fail("Duplicate token generated");
} else{
set.add(token);
}
}
}