我一直在寻找一种简单的Java算法来生成伪随机字母数字字符串。在我的情况下,它将被用作唯一的会话/密钥标识符,“很可能”在超过50万代的时间内是唯一的(我的需求实际上不需要更复杂的东西)。
理想情况下,我可以根据我的独特性需求指定长度。例如,生成的长度为12的字符串可能看起来像“AEYGF7K0DM1X”。
我一直在寻找一种简单的Java算法来生成伪随机字母数字字符串。在我的情况下,它将被用作唯一的会话/密钥标识符,“很可能”在超过50万代的时间内是唯一的(我的需求实际上不需要更复杂的东西)。
理想情况下,我可以根据我的独特性需求指定长度。例如,生成的长度为12的字符串可能看起来像“AEYGF7K0DM1X”。
当前回答
这里有一个简单的一行代码,使用UUID作为字符基础,可以指定(几乎)任何长度。(是的,我知道以前有人建议使用UUID。)
public static String randString(int length) {
return UUID.randomUUID().toString().replace("-", "").substring(0, Math.min(length, 32)) + (length > 32 ? randString(length - 32) : "");
}
其他回答
我不太喜欢这些关于“简单”解决方案的答案:S
我会选择简单的;),纯Java,一行(熵基于随机字符串长度和给定字符集):
public String randomString(int length, String characterSet) {
return IntStream.range(0, length).map(i -> new SecureRandom().nextInt(characterSet.length())).mapToObj(randomInt -> characterSet.substring(randomInt, randomInt + 1)).collect(Collectors.joining());
}
@Test
public void buildFiveRandomStrings() {
for (int q = 0; q < 5; q++) {
System.out.println(randomString(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")); // The character set can basically be anything
}
}
或者(更易读的老方法)
public String randomString(int length, String characterSet) {
StringBuilder sb = new StringBuilder(); // Consider using StringBuffer if needed
for (int i = 0; i < length; i++) {
int randomInt = new SecureRandom().nextInt(characterSet.length());
sb.append(characterSet.substring(randomInt, randomInt + 1));
}
return sb.toString();
}
@Test
public void buildFiveRandomStrings() {
for (int q = 0; q < 5; q++) {
System.out.println(randomString(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")); // The character set can basically be anything
}
}
但另一方面,你也可以使用UUID,它具有相当好的熵:
UUID.randomUUID().toString().replace("-", "")
在前面的答案中有很多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);
}
高效而简短。
/**
* 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();
}
}
如果您愿意使用Apache类,可以使用org.Apache.mons.text.RandomStringGenerator(Apache commons文本)。
例子:
RandomStringGenerator randomStringGenerator =
new RandomStringGenerator.Builder()
.withinRange('0', 'z')
.filteredBy(CharacterPredicates.LETTERS, CharacterPredicates.DIGITS)
.build();
randomStringGenerator.generate(12); // toUpperCase() if you want
自Apache Commons Lang 3.6以来,RandomStringUtils已被弃用。
我找到了生成随机十六进制编码字符串的解决方案。所提供的单元测试似乎符合我的主要用例。虽然,它比提供的一些其他答案稍微复杂一些。
/**
* 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);
}
}
}