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

вопрос создан в Fri, Feb 1, 2019 12:00 AM

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

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

    
1617
  1. 2010-10-25 15: 07: 51Z
  2. Даже принимая во внимание парадокс дня рождения, если вы используете 12 буквенно-цифровых символов (всего 62), вам все равно понадобится более 34 миллиардов строк, чтобы достичь парадокса. И парадокс дня рождения не гарантирует столкновения в любом случае, он просто говорит, что вероятность более 50%.
    2012-10-29 04: 13: 10Z
  3. @ NullUserException Вероятность успеха 50% (за попытку) чертовски высока: даже при 10 попытках вероятность успеха составляет 0,999. Учитывая это и тот факт, что вы можете попробовать ЛОТ в течение 24 часов, вам не нужно 34 миллиарда строк, чтобы быть уверенным, чтобы угадать хотя бы одну из них. Вот почему некоторые сессионные токены должны быть очень, очень длинными.
    2015-01-31 10: 28: 30Z
  4. Думаю, эти 3 однострочных кода очень полезны .. Long.toHexString(Double.doubleToLongBits(Math.random())); UUID.randomUUID().toString(); RandomStringUtils.randomAlphanumeric(12);
    2016-06-08 07: 31: 33Z
  5. @ Pijusn Я знаю, что это старо, но ... "50% -ый шанс" в парадоксе дня рождения - НЕ "на попытку" , "50% вероятности того, что из (в данном случае) 34 миллиардов строк существует хотя бы одна пара дубликатов". Вам понадобится 1.6 sept illion - 1.6e21 - записей в вашей базе данных, чтобы иметь шанс 50% на попытку.
    2017-10-11 19: 21: 33Z
30 ответов                              30                         

Алгоритм

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

Реализация

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

 
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. Для чисто внутреннего использования они могут быть неэффективными.

    
1488
2019-02-11 01: 18: 21Z
  1. Если вам нужны пробелы в вашем, вы можете добавить .replaceAll("\\d", " "); в конец строки return new BigInteger(130, random).toString(32);, чтобы выполнить подстановку регулярных выражений. Он заменяет все цифры пробелами. Прекрасно работает для меня: я использую это вместо внешнего интерфейса Lorem Ipsum
    2011-10-07 15: 00: 05Z
  2. @ weisjohn Это хорошая идея. Вы можете сделать что-то похожее со вторым методом, убрав цифры из symbols и используя вместо них пробел; Вы можете контролировать среднюю длину слова, изменяя количество пробелов в символах (больше случаев для более коротких слов). Для по-настоящему фальшивого текстового решения вы можете использовать цепочку Маркова!
    2011-10-07 16: 02: 33Z
  3. Я пробовал это, но иногда это только 31 долго.
    2011-12-19 23: 46: 09Z
  4. Почему .toString (32), а не .toString (36)?
    2012-02-21 19: 13: 40Z
  5. @ ejain потому что 32 = 2 ^ 5; каждый символ будет представлять ровно 5 битов, а 130 битов могут быть равномерно разделены на символы.
    2012-02-21 21: 38: 01Z

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
    
782
2017-08-30 06: 09: 52Z
  1. Помните, что это решение генерирует только случайную строку с шестнадцатеричными символами. Что может быть хорошо в некоторых случаях.
    2011-05-05 09: 28: 17Z
  2. Класс UUID полезен. Однако он не такой компактный, как идентификаторы, полученные из моих ответов. Это может быть проблемой, например, в URL. Зависит от ваших потребностей.
    2011-08-24 16: 37: 45Z
  3. @ Ruggs. Цель - буквенно-цифровые строки. Как с этим согласуется расширение вывода до любых возможных байтов?
    2011-10-07 16: 18: 53Z
  4. Согласно RFC4122 использование UUID в качестве токенов является плохой идеей: не предполагайте, что UUID трудно угадать; например, их не следует использовать в качестве средств защиты (идентификаторов, чье простое владение предоставляет доступ). Предсказуемый источник случайных чисел усугубит ситуацию. ietf.org/rfc/rfc4122.txt
    2012-12-31 11: 31: 04Z
  5. UUID.randomUUID().toString().replaceAll("-", ""); делает строку буквенно-цифровой по запросу.
    2014-01-22 09: 58: 08Z
 
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();
}
    
519
2016-02-25 10: 41: 59Z
  1. + 1, самое простое решение для генерации случайной строки указанной длины (кроме использования RandomStringUtils из Commons Lang).
    2012-04-20 15: 49: 23Z
  2. Попробуйте использовать SecureRandom вместо класса Random. Если пароли генерируются на сервере, он может быть уязвим для временных атак.
    2014-06-25 13: 34: 44Z
  3. Я бы также добавил строчные буквы: AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; и некоторые другие разрешенные символы.
    2015-09-07 20: 56: 11Z
  4. Почему бы не поместить static Random rnd = new Random(); в метод?
    2016-02-08 01: 25: 50Z
  5. @ MicroR Есть ли веская причина для создания объекта Random при каждом вызове метода? Я так не думаю.
    2016-02-15 10: 49: 55Z

Если вы счастливы использовать классы 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 устарела.

    
474
2017-10-18 07: 58: 04Z
  1. Только что просмотрел упомянутый класс из библиотеки Apache Commons Lang 3.3.1 - и использует только java.util.Random для предоставления случайных последовательностей, поэтому он производит небезопасные последовательности .
    2014-04-03 14: 51: 29Z
  2. Убедитесь, что вы используете 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)
    2015-03-03 13: 28: 02Z
  3. НЕ ИСПОЛЬЗОВАТЬ. Это создает небезопасные последовательности !
    2019-04-04 13: 03: 27Z

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

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

http://mynotes.wordpress.com/2009 /07/23 /Java-генерирующей-случайная строка / р>     

104
2015-10-29 02: 29: 50Z
  1. Но только 6 букв: (
    2011-01-11 09: 45: 12Z
  2. Мне это тоже помогло, но только шестнадцатеричные цифры: (
    2011-09-05 05: 31: 46Z
  3. @ Zippoxer, вы можете согласовать это несколько раз =)
    2014-05-17 15: 10: 10Z
  4. В примере OP была показана следующая строка в качестве примера AEYGF7K0DM1X, которая не является шестнадцатеричной. Меня беспокоит, как часто люди ошибочно принимают буквенно-цифровые и шестнадцатеричные числа. Это не одно и то же.
    2014-11-20 02: 31: 59Z
  5. Это гораздо менее случайно, чем следует задавать длиной строки, так как Math.random() выдает double между 0 и 1, поэтому часть экспоненты в основном не используется. Используйте random.nextLong для случайного long вместо этого безобразного хака.
    2015-07-22 01: 13: 22Z

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

RandomStringUtils.randomAlphanumeric(20).toUpperCase();
    
100
2014-12-09 14: 15: 43Z
  1. @ kamil, я посмотрел исходный код для RandomStringUtils, и он использует экземпляр java.util.Random, созданный без аргументов. Документация для java.util.Random говорит, что он использует текущее системное время, если начальное число не предоставлено. Это означает, что его нельзя использовать для идентификаторов /ключей сеанса, так как злоумышленник может легко предсказать, какими будут сгенерированные идентификаторы сеанса в любой момент времени.
    2012-09-26 10: 14: 26Z
  2. @ Inshallah: Вы (излишне) перерабатываете систему. Хотя я согласен с тем, что он использует время в качестве начального числа, злоумышленник должен иметь доступ к следующим данным, чтобы фактически получить то, что он хочет 1. Время с точностью до миллисекунды, когда код был заполнен 2. Число вызовов, которые были выполнены до настоящего времени 3. Атомность для его собственного вызова (так что количество вызовов до сих пор остается одинаковым). Если у вашего злоумышленника есть все эти три вещи, то у вас под рукой гораздо большая проблема ...
    2013-10-13 23: 36: 41Z
  3. зависимость от gradle: compile 'commons-lang:commons-lang:2.6'
    2015-01-19 14: 35: 30Z
  4. @ Ajeet это не так. Вы можете получить состояние генератора случайных чисел из его выходных данных. Если злоумышленник может сгенерировать несколько тысяч вызовов для генерации случайных токенов API, злоумышленник сможет предсказать все будущие токены API.
    2016-12-20 13: 52: 09Z
  5. @ AjeetGanga Ничего общего с чрезмерным проектированием. Если вы хотите создать идентификаторы сеанса, вам нужен криптографический генератор псевдослучайных данных. Каждый prng, использующий время в качестве начального числа, предсказуем и очень небезопасен для данных, которые должны быть непредсказуемыми. Просто используйте SecureRandom, и все хорошо.
    2017-09-19 10: 37: 55Z

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

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

 сравнение размеров токенов

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

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

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

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

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

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

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

Дополнительные кодировки, такие как 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

Пример: генератор токенов Base64 (безопасный URL)

 
public static String generateRandomBase64Token(int byteLength) {
    SecureRandom secureRandom = new SecureRandom();
    byte[] token = new byte[byteLength];
    secureRandom.nextBytes(token);
    return Base64.getUrlEncoder().withoutPadding().encodeToString(token); //base64 encoding
}

//generateRandomBase64Token(16) -> EEcCCAYuUcQk7IuzdaPzrg

Пример: Java CLI Tool

Если вам нужен готовый инструмент cli, вы можете использовать игральные кости: https://github.com/patrickfav /кости р>     

61
2019-04-04 13: 17: 52Z
  1. Этот ответ завершен и работает без добавления каких-либо зависимостей. Если вы хотите избежать возможных минус в выходных данных, вы можете предотвратить отрицательные BigInteger с, используя параметр конструктора: BigInteger(1, token) вместо BigInteger(token).
    2017-07-11 07: 50: 45Z
  2. Танки @francoisr для подсказки, я отредактировал пример кода
    2017-07-11 08: 38: 39Z
  3. import java.security.SecureRandom; и import java.math.BigInteger; необходимы для работы примера, но он отлично работает!
    2018-10-04 01: 45: 45Z

использовать доллар должно быть просто, как:

 
// "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
    
42
2015-10-29 02: 30: 13Z
  1. возможно ли использовать SecureRandom с shuffle?
    2016-11-16 10: 58: 23Z

Вот это на 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
    
32
2008-09-03 17: 16: 38Z
  1. Это создаст небезопасные последовательности , то есть последовательности, которые можно легко угадать.
    2014-04-03 14: 53: 58Z
  2. и leftPad ????
    2015-03-19 17: 53: 19Z
  3. Вся эта случайная генерация случайных чисел с двойным заражением нарушена дизайном, медленная и нечитаемая Используйте Random#nextInt или nextLong. При необходимости переключитесь на SecureRandom.
    2015-07-22 01: 17: 11Z

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

 
import java.util.UUID

UUID.randomUUID().toString();

Легко.

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

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

  

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

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

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

    

32
2014-04-16 11: 49: 00Z
  1. Кто-то это предложил, примерно за год до вас.
    2013-09-10 04: 49: 58Z

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

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

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

    
27
2018-04-02 23: 29: 20Z
  1. Просто имейте в виду, что с вероятностью 50% от знака минус перед результатом! Таким образом, можно использовать функцию r.nextLong () в Math.abs (), если вы не хотите использовать знак минус: Long.toString(Math.abs(r.nextLong()), 36);
    2013-01-27 02: 12: 03Z
  2. @ RayHulha: Если вам не нужен знак минус, вы должны его отключить, потому что, как ни странно, Math.abs возвращает отрицательное значение для Long.MIN_VALUE.
    2013-01-27 13: 28: 49Z
  3. Интересно, что Math.abs возвращает отрицательный результат. Подробнее здесь: bmaurer.blogspot.co.nz/2006 /10 /...
    2013-11-10 20: 34: 20Z
  4. Проблема с abs решается с помощью побитового оператора для сброса наиболее значимого бита. Это будет работать для всех значений.
    2018-04-02 23: 27: 35Z
  5. @ Radiodef По сути, это то, что сказал @userunkown. Я полагаю, вы могли бы также сделать << 1 >>> 1.
    2018-04-02 23: 35: 00Z

Альтернатива в 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();
}
    
15
2018-10-03 19: 09: 43Z
  1. Это замечательно, но если вы хотите, чтобы оно было строго буквенно-цифровым (0-9, az, AZ), см. здесь realjava.com/2015/06/…
    2015-06-23 14: 08: 13Z
 
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;
}
    
11
2012-10-09 04: 47: 13Z
  1. Это действительно полезно.
    2016-09-02 08: 41: 31Z

Использование 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. Последняя проблема: если нам нужна строка определенной длины, случайное число может сгенерировать небольшое число, поэтому длина не будет достигнута, поэтому мы должны дополнить строку требуемой длиной, добавляя нули.

    
11
2016-03-11 10: 56: 42Z
  1. не могли бы вы объяснить лучше 5?
    2016-03-09 16: 56: 27Z
  2. спасибо! это намного лучше!
    2016-03-11 11: 50: 27Z
 
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);
    }
}

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

    
10
2012-04-17 09: 42: 20Z
  1. Я позволил себе внести некоторые незначительные изменения. Почему вы добавляете + 0 так часто? Почему вы разделяете объявление о месте и инициализации? В чем преимущество индексов 1,2,3,4 вместо 0,1,2,3? Самое главное: вы взяли случайное значение и сравнили с новым значением 4 раза, которое всегда могло не совпадать, не получая больше случайности. Но не стесняйтесь откат.
    2012-04-17 09: 50: 59Z

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

 
/**
 * 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);
        }
    }
}
    
8
2015-08-20 06: 49: 20Z
  1. Я не думаю, что было бы справедливо провалиться на дубликаты токенов, которые основаны исключительно на вероятности.
    2012-06-02 15: 22: 33Z
 
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;
    }
}
    
8
2015-08-20 06: 50: 34Z
 
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);
        }
    }
}
    
7
2015-08-20 06: 51: 18Z
  1. Измените строковые символы в соответствии с вашими требованиями.

    я>
  2. Строка является неизменной. Здесь 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();
    }
    
7
2017-07-31 17: 14: 09Z
  1. Это ничего не добавляет к десяткам ответов, которые ранее не были рассмотрены. И создание нового экземпляра Random в каждой итерации цикла неэффективно.
    2014-02-10 05: 17: 52Z

Не очень нравится любой из этих ответов относительно "простого" решения: 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("-", "")

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

    
7
2018-02-21 15: 55: 12Z

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

    
6
2017-06-26 22: 47: 13Z
  1. Ссылка не работает: github.com/zhelev/jpwgen
    2017-06-25 01: 27: 57Z
  2. Спасибо, исправили. Так что по крайней мере, есть источник и ссылка действительна. С другой стороны, не похоже, что он обновлялся в течение некоторого времени, хотя я вижу, что pwgen был обновлен довольно недавно.
    2017-06-26 22: 50: 50Z

Вот решение Scala:

 
(for (i <- 0 until rnd.nextInt(64)) yield { 
  ('0' + rnd.nextInt(64)).asInstanceOf[Char] 
}) mkString("")
    
4
2012-07-24 11: 11: 01Z

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

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

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

    
4
2013-07-29 14: 07: 23Z
  1. Почему в мире вы используете UUID для получения случайных битов? Почему бы просто не использовать random.nextLong()? Или даже Double.doubleToLongBits(Math.random())?
    2013-10-04 05: 31: 50Z

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

 
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
2015-08-20 06: 52: 26Z

Вот однострочный код от 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
2019-01-29 06: 07: 59Z

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

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

вот документ http: //commons .apache.org /языки /API-2,3 /орг /Apache /обыкновенные /языки /RandomStringUtils.html р>     

3
2012-10-15 07: 52: 12Z
  1. Уже предложено несколько месяцев назад.
    2013-10-04 05: 43: 19Z
 
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;
}
    
3
2018-04-02 23: 30: 48Z
  1. Такая конкатенация строк неоправданно неэффективна. И сумасшедший отступ делает ваш код почти нечитаемым. Это то же самое, что и идея Джейми, , но плохо выполненная.
    2013-10-04 05: 36: 49Z

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

 
 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
2018-11-26 18: 31: 13Z
 
public static String getRandomString(int length) 
{
   String randomStr = UUID.randomUUID().toString();
   while(randomStr.length() < length) {
       randomStr += UUID.randomUUID().toString();
   }
   return randomStr.substring(0, length);
}
    
2
2012-12-03 06: 59: 05Z
  1. Это в значительной степени совпадает с ответом Стива Маклеода двумя годами ранее.
    2013-10-04 05: 40: 15Z

Может быть, это полезно

 
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
2017-06-28 09: 49: 48Z
источник размещен Вот
Другие вопросы