Как сгенерировать случайную буквенно-цифровую строку?

1578

Я искал простой алгоритм Java для генерации псевдослучайной буквенно-цифровой строки. В моей ситуации он будет использоваться в качестве уникального идентификатора сеанса/ключа, который "вероятно" будет уникальным в течение поколения 500K+ (мои потребности на самом деле не требуют ничего более сложного).

В идеале я мог бы указать длину в зависимости от моих потребностей уникальности. Например, сгенерированная строка длиной 12 может выглядеть примерно так: "AEYGF7K0DM1X".

  • 134
    Остерегайтесь парадокса дня рождения .
  • 52
    Даже принимая во внимание парадокс дня рождения, если вы используете 12 буквенно-цифровых символов (всего 62), вам все равно понадобится более 34 миллиардов строк, чтобы достичь парадокса. И парадокс дня рождения не гарантирует столкновения в любом случае, он просто говорит, что вероятность более 50%.
Показать ещё 7 комментариев
Теги:
string
random
alphanumeric

46 ответов

1541
Лучший ответ

Алгоритм

Чтобы сгенерировать случайную строку, объедините символы, нарисованные случайным образом из набора допустимых символов, пока строка не достигнет желаемой длины.

Реализация

Вот несколько довольно простых и очень гибких кодов для генерации случайных идентификаторов. Прочитайте информацию, которая следует для важных замечаний по применению.

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-адреса или введены вручную.

Основной источник случайности или энтропии для идентификаторов сеансов должен исходить от генератора случайных чисел, предназначенного для криптографии. Однако инициализация этих генераторов иногда может быть вычислительно дорогой или медленной, поэтому следует предпринять усилия для их повторного использования, когда это возможно.

Использовать в качестве идентификаторов объектов

Не каждое приложение требует безопасности. Случайное назначение может быть эффективным способом для нескольких объектов генерировать идентификаторы в совместно используемом пространстве без какой-либо координации или разделения. Координация может быть медленной, особенно в кластерной или распределенной среде, а разделение пространства вызывает проблемы, когда объекты в конечном итоге получают слишком маленькие или слишком большие ресурсы.

Идентификаторы, сгенерированные без принятия мер по их непредсказуемости, должны быть защищены другими средствами, если злоумышленник сможет их просматривать и манипулировать, как это происходит в большинстве веб-приложений. Должна быть отдельная система авторизации, которая защищает объекты, чей идентификатор может быть угадан злоумышленником без разрешения доступа.

Также следует позаботиться о том, чтобы использовать идентификаторы, достаточно длинные, чтобы сделать коллизии маловероятными, учитывая ожидаемое общее количество идентификаторов. Это называется "парадоксом дня рождения". Вероятность столкновения, p, приблизительно равна n 2/(2q x), где n - количество фактически сгенерированных идентификаторов, q - количество различных символов в алфавите, а x - длина идентификаторов. Это должно быть очень маленькое число, например, 2-50 или меньше.

Выработка этого показывает, что вероятность столкновения между 500k 15-символьными идентификаторами составляет около 2–52 что, вероятно, менее вероятно, чем необнаруженные ошибки космических лучей и т.д.

Сравнение с UUID

Согласно их спецификации, UUID не предназначены для непредсказуемости и не должны использоваться в качестве идентификаторов сеанса.

UUID в их стандартном формате занимают много места: 36 символов только для 122 бит энтропии. (Не все биты "случайного" UUID выбираются случайным образом.) Случайно выбранная буквенно-цифровая строка упаковывает больше энтропии всего в 21 символ.

UUID не являются гибкими; они имеют стандартизированную структуру и расположение. Это их главное достоинство, а также их главная слабость. При сотрудничестве с внешней стороной может оказаться полезной стандартизация, предлагаемая UUID. Для чисто внутреннего использования они могут быть неэффективными.

  • 0
    Ваш дорогой способ не работает для меня! я получаю не могу найти символ для метода BigInteger (int, java.security.SecureRandom)
  • 3
    Если вам нужны пробелы в вашем, вы можете использовать .replaceAll("\\d", " "); в конце return new BigInteger(130, random).toString(32); линия, чтобы сделать регулярное свопинг. Он заменяет все цифры пробелами. Прекрасно работает для меня: я использую это вместо внешнего интерфейса Lorem Ipsum
Показать ещё 54 комментария
777

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
  • 28
    Помните, что это решение генерирует только случайную строку с шестнадцатеричными символами. Что может быть хорошо в некоторых случаях.
  • 5
    Класс UUID полезен. Однако они не так компактны, как идентификаторы, полученные в моих ответах. Это может быть проблемой, например, в URL. Зависит от ваших потребностей.
Показать ещё 12 комментариев
491

Если вы счастливы использовать классы Apache, вы можете использовать org.apache.commons.text.RandomStringGenerator (commons-text).

Пример:

RandomStringGenerator randomStringGenerator =
        new RandomStringGenerator.Builder()
                .withinRange('0', 'z')
                .filteredBy(CharacterPredicates.LETTERS, CharacterPredicates.DIGITS)
                .build();
randomStringGenerator.generate(12); // toUpperCase() if you want

Так как commons-lang 3.6, RandomStringUtils устарел.

  • 21
    Только что просмотрел упомянутый класс библиотеки Apache Commons Lang 3.3.1 - и использует только java.util.Random для предоставления случайных последовательностей, поэтому он создает небезопасные последовательности .
  • 15
    Убедитесь, что вы используете SecureRandom при использовании RandomStringUtils: public static java.lang.String random(int count, int start, int end, boolean letters, boolean numbers, @Nullable char[] chars, java.util.Random random)
481
static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static SecureRandom rnd = new SecureRandom();

String randomString( int len ){
   StringBuilder sb = new StringBuilder( len );
   for( int i = 0; i < len; i++ ) 
      sb.append( AB.charAt( rnd.nextInt(AB.length()) ) );
   return sb.toString();
}
  • 56
    +1, самое простое решение для генерации случайной строки заданной длины (кроме использования RandomStringUtils из Commons Lang).
  • 11
    Попробуйте использовать SecureRandom вместо класса Random . Если пароли генерируются на сервере, он может быть уязвим для временных атак.
Показать ещё 6 комментариев
101

Вы можете использовать библиотеку Apache для этого: RandomStringUtils

RandomStringUtils.randomAlphanumeric(20).toUpperCase();
  • 0
    Гарантирует ли эта функция генерировать уникальные результаты при вызове в разное время?
  • 17
    @kamil, я посмотрел исходный код для RandomStringUtils, и он использует экземпляр java.util.Random, созданный без аргументов. Документация для java.util.Random говорит, что она использует текущее системное время, если начальное число не предоставлено. Это означает, что он не может использоваться для идентификаторов / ключей сеанса, поскольку злоумышленник может легко предсказать, что представляют собой сгенерированные идентификаторы сеанса в любой момент времени.
Показать ещё 7 комментариев
100

В одной строке:

Long.toHexString(Double.doubleToLongBits(Math.random()));

http://mynotes.wordpress.com/2009/07/23/java-generating-random-string/

  • 8
    Но только 6 букв :(
  • 2
    Это мне тоже помогло, но только шестнадцатеричные цифры :(
Показать ещё 4 комментария
48

Это легко достижимо без каких-либо внешних библиотек.

1. Криптографическая генерация псевдослучайных данных

Сначала вам нужен криптографический PRNG. В Java есть SecureRandom для которого обычно используется лучший источник энтропии на машине (например, /dev/random). Узнайте больше здесь.

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

Примечание. SecureRandom - самый медленный, но наиболее безопасный способ создания случайных байтов в Java. Однако я рекомендую НЕ рассматривать производительность здесь, поскольку она обычно не оказывает реального влияния на ваше приложение, если вам не нужно генерировать миллионы токенов в секунду.

2. Требуемое пространство возможных значений

Затем вы должны решить, насколько уникальным должен быть ваш токен. Единственный смысл рассмотрения энтропии состоит в том, чтобы убедиться, что система может противостоять атакам с использованием грубой силы: пространство возможных значений должно быть настолько большим, чтобы любой злоумышленник мог испробовать лишь незначительную долю значений в нелепое время 1. Уникальные идентификаторы, такие как случайный UUID имеют 122-битную энтропию (т.е. 2 ^ 122 = 5,3x10 ^ 36) - вероятность столкновения равна "* (...), так как вероятность дублирования составляет один на миллиард, 103 триллиона UUID версии 4 должны быть сгенерированы 2 ". Мы выберем 128 бит, так как он вписывается точно в 16 байтов и считается весьма достаточным для того, чтобы быть уникальным в основном для каждого, но наиболее экстремального варианта использования, и вам не нужно думать о дубликатах. Вот простая таблица сравнения энтропии, включая простой анализ проблемы дня рождения.

Изображение 1323

Для простых требований может быть достаточно 8 или 12 байтов, но с 16 байтами вы на "безопасной стороне".

И это в основном это. И последнее, что нужно подумать о кодировке, чтобы она могла быть представлена в виде печатного текста (читай, String).

3. Бинарное в текстовое кодирование

Типичные кодировки включают в себя:

  • Base64 каждый символ кодирует 6 бит, создавая 33% накладных расходов. К сожалению, в JDK нет стандартной реализации (7 и ниже - есть в Android и Java 8+). Но существуют многочисленные библиотеки, которые добавляют это. Недостатком является то, что стандарт Base64 небезопасен, например. urls и в качестве имени файла в большинстве файловых систем, требующих дополнительной кодировки (например, кодировка url) или безопасной версии URL Base64. Пример кодирования 16 байтов с заполнением: XfJhfv3C0P6ag7y9VQxSbw==

  • Base32 каждый символ кодирует 5 бит, создавая 40% накладных расходов. При этом будут использоваться AZ и 2-7 что делает его достаточно экономным при сохранении буквенно-цифрового значения без учета регистра. В JDK нет стандартной реализации. Пример кодирования 16 байтов без заполнения: WUPIL5DQTZGMF4D3NX5L7LNFOY

  • Base16 (шестнадцатеричный) каждый символ кодирует 4 бита, требуя 2 символа на байт (т.е. 16 байт создают строку длиной 32). Поэтому hex меньше места, чем Base32 но в большинстве случаев безопасно использовать (url), поскольку он использует только 0-9 и от A до F Пример кодирования 16 байтов: 4fa3dd0f57cb3bf331441ed285b27735. Смотрите ТАКОЕ обсуждение конвертации в hex здесь.

Дополнительные кодировки, такие как Base85 и экзотическая Base122, существуют с лучшей/худшей эффективностью пространства. Вы можете создать свою собственную кодировку (что в основном делает большинство ответов в этой теме), но я бы посоветовал против этого, если у вас нет особых требований. Смотрите больше схем кодирования в статье Википедии.

4. Резюме и пример

  • Используйте SecureRandom
  • Используйте не менее 16 байтов (2 ^ 128) возможных значений
  • Кодировать в соответствии с вашими требованиями (обычно hex или base32 если вам нужно, чтобы оно было буквенно-цифровым)

не

  • ... используйте кодировку домашнего приготовления: лучше обслуживаемую и удобочитаемую для других, если они видят, какую стандартную кодировку вы используете вместо странных для циклов, создающих символы одновременно.
  • ... использовать 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/dice

  • 1
    Этот ответ является полным и работает без добавления каких-либо зависимостей. Если вы хотите избежать возможных отрицательных знаков в выходных данных, вы можете предотвратить отрицательные значения BigInteger используя параметр конструктора: BigInteger(1, token) вместо BigInteger(token) .
  • 0
    Танки @francoisr за подсказку, я редактировал пример кода
Показать ещё 1 комментарий
43

с помощью Dollar должно быть простым:

// "0123456789" + "ABCDE...Z"
String validCharacters = $('0', '9').join() + $('A', 'Z').join();

String randomString(int length) {
    return $(validCharacters).shuffle().slice(length).toString();
}

@Test
public void buildFiveRandomStrings() {
    for (int i : $(5)) {
        System.out.println(randomString(12));
    }
}

выводится что-то вроде этого:

DKL1SBH9UJWC
JH7P0IT21EA5
5DTI72EO6SFU
HQUMJTEBNF7Y
1HCR6SKYWGT7
  • 0
    Можно ли использовать SecureRandom с shuffle?
31

Удивительно, что никто здесь не предложил, но:

import java.util.UUID

UUID.randomUUID().toString();

Легко.

Преимущество этого заключается в том, что UUID хорошо и долго и гарантированно почти невозможно столкнуться.

В Википедии есть хорошее объяснение:

"... только после генерации 1 миллиарда UUID каждую секунду в течение следующих 100 лет вероятность создания всего одного дубликата составит около 50%.

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

Первые 4 бита - это тип версии и 2 для варианта, поэтому вы получаете 122 бита случайных значений. Поэтому, если вы хотите, вы можете усекать с конца, чтобы уменьшить размер UUID. Он не рекомендуется, но у вас все еще есть множество случайностей, достаточно для ваших записей 500k.

31

Здесь он находится в 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
  • 4
    Это создаст небезопасные последовательности, то есть последовательности, которые можно легко угадать.
  • 0
    и левый планшет ????
Показать ещё 1 комментарий
26

Краткое и простое решение, но использует только строчные буквы и цифры:

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

Размер составляет от 12 цифр до основания 36 и не может быть улучшен дальше, таким образом. Конечно, вы можете добавить несколько экземпляров.

  • 10
    Просто имейте в виду, что есть 50% -ная вероятность того, что знак минус окажется перед результатом! Таким образом, можно обернуть r.nextLong () в Math.abs (), если вам не нужен знак минус: Long.toString(Math.abs(r.nextLong()), 36);
  • 5
    @RayHulha: Если вам не нужен знак минус, вы должны его обрезать, потому что, как ни странно, Math.abs возвращает отрицательное значение для Long.MIN_VALUE.
Показать ещё 3 комментария
13

Альтернативой в Java 8 является:

static final Random random = new Random(); // Or SecureRandom
static final int startChar = (int) '!';
static final int endChar = (int) '~';

static String randomString(final int maxLength) {
  final int length = random.nextInt(maxLength + 1);
  return random.ints(length, startChar, endChar + 1)
        .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
        .toString();
}
  • 3
    Это здорово - но если вы хотите, чтобы оно было строго буквенно-цифровым (0-9, az, AZ), см. Здесьrealjava.com/ 2015/06/…
10

Использование 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 и символы a-z, нам понадобится случайное число от 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 символа (w-z). Чтобы сгенерировать строку определенной длины, мы можем просто использовать число 2^(length*numBits)-1. Последняя проблема, если нам нужна строка с определенной длиной, random может генерировать небольшое число, поэтому длина не выполняется, поэтому нам нужно наложить строку на требуемую длину, предваряющую нули.

  • 0
    не могли бы вы объяснить лучше 5?
  • 0
    Спасибо! это намного лучше!
10
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;
}
  • 0
    Это действительно полезно.
9
import java.util.Random;

public class passGen{
    //Verison 1.0
    private static final String dCase = "abcdefghijklmnopqrstuvwxyz";
    private static final String uCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final String sChar = "!@#$%^&*";
    private static final String intChar = "0123456789";
    private static Random r = new Random();
    private static String pass = "";

    public static void main (String[] args) {
        System.out.println ("Generating pass...");
        while (pass.length () != 16){
            int rPick = r.nextInt(4);
            if (rPick == 0){
                int spot = r.nextInt(25);
                pass += dCase.charAt(spot);
            } else if (rPick == 1) {
                int spot = r.nextInt (25);
                pass += uCase.charAt(spot);
            } else if (rPick == 2) {
                int spot = r.nextInt (7);
                pass += sChar.charAt(spot);
            } else if (rPick == 3){
                int spot = r.nextInt (9);
                pass += intChar.charAt (spot);
            }
        }
        System.out.println ("Generated Pass: " + pass);
    }
}

Итак, что это значит, просто добавьте пароль в строку и... да, хорошо проверите это... очень просто. Я написал его

  • 0
    Я позволил себе сделать небольшие изменения. Почему вы добавляете + 0 часто? Почему вы разделяете объявление о месте и инициализации? В чем преимущество индексов 1,2,3,4 вместо 0,1,2,3? Самое главное: вы взяли случайное значение и сравнили с новым значением 4 раза, которое всегда могло не совпадать, не получая больше случайности. Но не стесняйтесь откат.
7
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;
    }
}
7

Я нашел это решение, которое генерирует случайную шестнадцатеричную кодированную строку. Предоставленный unit test, похоже, поддерживает мой основной вариант использования. Хотя, это немного сложнее, чем некоторые другие ответы.

/**
 * 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);
        }
    }
}
  • 0
    Я не думаю, что будет справедливо провалиться на дубликаты токенов, которые основаны исключительно на вероятности.
6

Не очень нравится любой из этих ответов относительно "простого" решения: 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"));//charachterSet 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")); //charachterSet can basically be anything
    }
}

Но, с другой стороны, вы также можете использовать UUID с довольно хорошей энтропией (https://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions):

UUID.randomUUID().toString().replace("-", "")

Надеюсь, это поможет.

6
  • Измените строковые символы в соответствии с вашими требованиями.

  • Строка неизменна. Здесь 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();
    }
  • 3
    Это не добавляет ничего, что десятки ответов, которые были даны ранее, не охватывали. И создание нового экземпляра Random в каждой итерации цикла неэффективно.
6
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);
        }
    }
}
5

Вы упоминаете "простой", но на всякий случай кто-то ищет что-то, что отвечает более строгим требованиям безопасности, вы можете взглянуть на jpwgen. jpwgen моделируется после pwgen в Unix и очень настраивается.

  • 1
    Ссылка не работает: github.com/zhelev/jpwgen
  • 0
    Спасибо, исправили это. Так что по крайней мере, есть источник и ссылка действительна. С другой стороны, не похоже, что он обновлялся в течение некоторого времени, хотя я вижу, что pwgen был обновлен довольно недавно.
4

Вот однострочный код от AbacusUtil

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

Случайный не означает, что он должен быть уникальным. чтобы получить уникальные строки, используя:

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

Вы можете использовать класс UUID с его сообщением getLeastSignificantBits() для получения 64 бит случайных данных, а затем преобразовать его в число радикса 36 (т.е. строку, состоящую из 0-9, A-Z):

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

Это дает строку длиной до 13 символов. Мы используем Math.abs(), чтобы убедиться, что нет знака минус.

  • 2
    Почему в мире вы использовали бы UUID, чтобы получить случайные биты? Почему бы просто не использовать random.nextLong() ? Или даже Double.doubleToLongBits(Math.random()) ?
4

Вы можете использовать следующий код, если ваш пароль обязательно содержит номера буквенных специальных символов:

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

}
4

Здесь это решение Scala:

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

Я думаю, что это самое маленькое решение здесь, или почти одно из самых маленьких:

 public String generateRandomString(int length) {
    String randomString = "";

    final char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890".toCharArray();
    final SecureRandom random = new SecureRandom();
    for (int i = 0; i < length; i++) {
        randomString = randomString + chars[random.nextInt(chars.length)];
    }

    return randomString;
}

Код работает очень хорошо. Если вы используете этот метод, я рекомендую вам использовать более 10 символов. Столкновение происходит с использованием 5 символов /30362 итераций. Это заняло 9 секунд.

3
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;
}
  • 2
    Эта конкатенация строк излишне неэффективна. И сумасшедший отступ делает ваш код почти нечитаемым. Это то же самое, что и идея Джейми, но плохо выполненная.
3

с использованием библиотеки apache это можно сделать в одной строке

import org.apache.commons.lang.RandomStringUtils;
RandomStringUtils.randomAlphanumeric(64);

здесь doc http://commons.apache.org/lang/api-2.3/org/apache/commons/lang/RandomStringUtils.html

2
public static String getRandomString(int length) {
        char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST".toCharArray();

        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < chars.length; i++) {
            char c = chars[random.nextInt(chars.length)];
            sb.append(c);
        }
        String randomStr = sb.toString();

        return randomStr;
    }
2

Возможно, это полезно

package password.generater;

import java.util.Random;

/**
 *
 * @author dell
 */
public class PasswordGenerater {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        int length= 11;
        System.out.println(generatePswd(length));

        // TODO code application logic here
    }
    static char[] generatePswd(int len){
        System.out.println("Your Password ");
        String charsCaps="ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
        String Chars="abcdefghijklmnopqrstuvwxyz";
        String nums="0123456789";
        String symbols="!@#$%^&*()_+-=.,/';:?><~*/-+";
        String passSymbols=charsCaps + Chars + nums +symbols;
        Random rnd=new Random();
        char[] password=new char[len];

        for(int i=0; i<len;i++){
            password[i]=passSymbols.charAt(rnd.nextInt(passSymbols.length()));
        }
      return password;

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

Вот решение Java 8, основанное на потоках.

    public String generateString(String alphabet, int length) {
        return generateString(alphabet, length, new SecureRandom()::nextInt);
    }

    // nextInt = bound -> n in [0, bound)
    public String generateString(String source, int length, IntFunction<Integer> nextInt) {
        StringBuilder sb = new StringBuilder();
        IntStream.generate(source::length)
                .boxed()
                .limit(length)
                .map(nextInt::apply)
                .map(source::charAt)
                .forEach(sb::append);

        return sb.toString();
    }

Используйте это как

String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int length = 12;
String generated = generateString(alphabet, length);
System.out.println(generated);

Функция nextInt должна принять ИНТ bound и возвращает случайное число между 0 и bound - 1.

1

Вы можете создать массив символов, который включает все буквы и цифры, затем вы можете случайно выбрать из этого массива char и создать свой собственный строковый пароль.

char[] chars = new char[62]; // sum of letters and numbers

int i = 0;

    for(char c = 'a'; c <= 'z';c++) { // for letters
        chars[i++] = c;
    }

    for(char c = '0'; c <= '9';c++) { // for numbers
        chars[i++] = c;
    }

    for(char c = 'A'; c <= 'Z';c++) { // for capital letters
        chars[i++] = c;
    }

    int numberOfCodes = 0;
    String code = "";
    while (numberOfCodes < 1) {//enter how much you want to generate at one time
        int numChars = 8; //Enter how many digits you want in your password

        for(i = 0; i < numChars; i++) {
            char c = chars[(int)(Math.random() * chars.length)];
            code = code + c;
        }
        System.out.println("Code is :" + code);
    }
  • 1
    Кажется, существенно дублирует мой ответ, который был дан два года назад.
1

Многое использование StringBuilder выше. Я думаю, это легко, но требует вызова функции за char, увеличения массива и т.д.... Если вы используете stringbuilder, предложение должно указать требуемую емкость строки, т.е.,

new StringBuilder(int capacity);

Здесь версия, которая не использует добавление StringBuilder или String, и словарь.

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

Лучший метод генератора случайных строк

public class RandomStringGenerator{

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

}
1

Я разработал приложение для создания автоматической сгенерированной буквенно-цифровой строки для моего проекта. В этой строке первые три символа являются алфавитными, а следующие семь - целыми числами.

public class AlphaNumericGenerator {

    public static void main(String[] args) {
        java.util.Random r = new java.util.Random();
        int i = 1, n = 0;
        char c;
        String str="";
        for (int t = 0; t < 3; t++) {
            while (true) {
                i = r.nextInt(10);
                if (i > 5 && i < 10) {

                    if (i == 9) {
                        i = 90;
                        n = 90;
                        break;
                    }
                    if (i != 90) {
                        n = i * 10 + r.nextInt(10);
                        while (n < 65) {
                            n = i * 10 + r.nextInt(10);
                        }
                    }

                    break;
                }
            }
            c=(char)n;

            str= String.valueOf(c)+str;
        }
        while(true){
        i = r.nextInt(10000000);
        if(i>999999)
            break;
        }
        str=str+i;
        System.out.println(str);

    }
}
0

Эффективный и короткий.

/**
 * 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();
    }

}
0

Здесь простой однострочный лайнер с использованием UUID в качестве базы символов и возможность указать (почти) любую длину. (Да, я знаю, что использование UUID было предложено раньше)

public static String randString(int length) {
    return UUID.randomUUID().toString().replace("-", "").substring(0, Math.min(length, 32)) + (length > 32 ? randString(length - 32) : "");
}
0

Для этого вы можете использовать небольшую математику и объект Random().

public static String RandomAlphaNumericString(int size){
    String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    String ret = "";
    int length = chars.length();
    for (int i = 0; i < size; i ++){
        ret += chars.split("")[ (int) (Math.random() * (length - 1)) ];
    }
    return ret;
}
0

Также вы можете генерировать любые нижние или верхние регистры Буквы или даже специальные символы, данные из таблицы ASCII. Например, создайте буквы верхнего регистра от A (DEC 65) до Z (DEC 90):

String generateRandomStr(int min, int max, int size) {
    String result = "";
    for (int i = 0; i < size; i++) {
        result += String.valueOf((char)(new Random().nextInt((max - min) + 1) + min));
    }
    return result;
}

Сгенерированный вывод для generateRandomStr (65, 90, 100));

TVLPFQJCYFXQDCQSLKUKKILKKHAUFYEXLUQFHDWNMRBIRRRWNXNNZQTINZPCTKLHGHVYWRKEOYNSOFPZBGEECFMCOKWHLHCEWLDZ
0

Еще одно решение.

public static String generatePassword(int passwordLength) {
    int asciiFirst = 33;
    int asciiLast = 126;
    Integer[] exceptions = { 34, 39, 96 };

    List<Integer> exceptionsList = Arrays.asList(exceptions);
    SecureRandom random = new SecureRandom();
    StringBuilder builder = new StringBuilder();
    for (int i=0; i<passwordLength; i++) {
        int charIndex;
        do {
            charIndex = random.nextInt(asciiLast - asciiFirst + 1) + asciiFirst;
        }
        while (exceptionsList.contains(charIndex));

        builder.append((char) charIndex);
    }

    return builder.toString();
}
-1

Случайная 10-строчная строка между верхним и нижним регистрами

StringBuilder randomString = new StringBuilder();   
Random random = new Random();
boolean alphaType = true;
int j;

for(int i = 0; i <= 9; ++i)
{
    j = (random.nextInt(25) + (alphaType == true ? 65 : 97));
    randomString.append((char)j);
    alphaType = !alphaType;
}
return randomString.toString();
  • 5
    Это не очень случайно (предсказуемо чередуется между прописными и строчными буквами) и не использует символы «0» - «9».
-2
/**
    Generate a random String with maxlength random
    characters found in the ASCII table between 33
    and 122 (so it contains every lowercase / uppercase
    letters, numbers and some others characters
*/
public static String GetRandomString(int maxlength)
{
    String result = "";
    int i = 0, n = 0, min = 33, max = 122;
    while(i < maxlength)
    {
        n = (int)(Math.random() * (max - min) + min);
        if(n >= 33 && n < 123)
        {
            result += (char)n;
            ++i;
        }
    }
    return(result);
}
-2

Вы можете использовать эту простую функцию java:

 public class GenerateRandomString {
   private static final String ALPHA_NUM =
           "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   public static void main(String[] args) {
      GenerateRandomString grs = new GenerateRandomString();
      System.out.println(grs.getAlphaNumeric(10));
      System.out.println(grs.getAlphaNumeric(20));
   }
   public String getAlphaNumeric(int len) {
      StringBuffer sb = new StringBuffer(len);
      for (int i=0;  i<len;  i++) {
         int ndx = (int)(Math.random()*ALPHA_NUM.length());
         sb.append(ALPHA_NUM.charAt(ndx));
      }
      return sb.toString();
   }
}
  • 2
    Чем он отличается по сути от первого ответа, полученного за два года до этого?
-3
public class RandomGenerator {
          private static SecureRandom prng;
          private static final Logger LOG = LoggerFactory
                    .getLogger(AuthTokenGenerator.class);
            static {
                try {
                    // Initialize SecureRandom
                    prng = SecureRandom.getInstance("SHA1PRNG");
                } catch (NoSuchAlgorithmException e) {
                    LOG.info("ERROR while intantiating Secure Random:   " + prng);
            }
        }
        /**
         * @return
         */
        public static String getToken() {
            try {
                LOG.info("About to Generate Token in getToken()");
                String token;
                // generate a random number
                String randomNum = Integer.toString(prng.nextInt());
                // get its digest
                MessageDigest sha = MessageDigest.getInstance("SHA-1");
                byte[] result = sha.digest(randomNum.getBytes());
                token = hexEncode(result);
                LOG.info("Token in getToken():   " + token);
                return token;
            } catch (NoSuchAlgorithmException ex) {
                return null;
            }
        }
        /**
         * @param aInput
         * @return
         */
        private static String hexEncode(byte[] aInput) {
            StringBuilder result = new StringBuilder();
            char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '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' };
            for (byte b : aInput) {
                result.append(digits[(b & 0xf0) >> 4]);
                result.append(digits[b & 0x0f]);
            }
            return result.toString();
        }
}
-7

Вы можете сделать это нелегко:

package gaming;

import java.util.Random;

public class game2 {

public static char c;
public static Random r = new Random();
public static int i = r.nextInt(25);
public static int i2 = r.nextInt(25);
public static int i3 = r.nextInt(25);
public static int i4= r.nextInt(25);
public static int i5 = r.nextInt(25);
public static int num2 = r.nextInt(9);
public static int num3= r.nextInt(9);
public static String s1 = String.valueOf(num2);
public static String s2 = String.valueOf(num3);

public static void main(String[] args){


    System.out.print("The pin is: ");
    changeToString(i);
    System.out.print(c);
    changeToString(i2);
    System.out.print(c);
    changeToString(i3);
    System.out.print(c);
    changeToString(i4);
    System.out.print(c);
    changeToString(i5);
    System.out.print(c);
    System.out.print(s1);
    System.out.print(s2);

}

public static void changeToString(int rand){

    switch (rand){

    case 0:

        c = 'A';
        break;
    case 1:

        c = 'B';
        break;
    case 2:

        c = 'C';
        break;
    case 3:

        c = 'D';
        break;
    case 4:

        c = 'E';
        break;
    case 5:

        c = 'F';
        break;
    case 6:

        c = 'G';
        break;
    case 7:

        c = 'H';
        break;
    case 8:

        c = 'I';
        break;
    case 9:

        c = 'J';
        break;
    case 10:

        c = 'K';
        break;
    case 11:

        c = 'L';
        break;
    case 12:

        c = 'M';
        break;
    case 13:

        c = 'N';
        break;
    case 14:

        c = 'O';
        break;
    case 15:

        c = 'P';
        break;
    case 16:

        c = 'Q';
        break;
    case 17:

        c = 'R';
        break;
    case 18:

        c = 'S';
        break;
    case 19:

        c = 'T';
        break;
    case 20:

        c = 'U';
        break;
    case 21:

        c = 'V';
        break;
    case 22:

        c = 'W';
        break;
    case 23:

        c = 'X';
        break;
    case 24:

        c = 'Y';
        break;
    case 25:

        c = 'Z';
        break;

    }

}
}
  • 4
    Святой Джеймс Гослинг, это самый ужасный код, который я когда-либо видел. Я прошу вас удалить это.
  • 0
    Пожалуйста, найдите работу в другой отрасли, ИТ не для вас.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню