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

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

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

3.09.2008 02:58:43
Остерегайтесь парадокса дня рождения .
pablosaraiva 25.10.2010 15:07:51
Даже принимая во внимание парадокс дня рождения, если вы используете 12 буквенно-цифровых символов (всего 62), вам все равно понадобится более 34 миллиардов строк, чтобы достичь парадокса. И парадокс дня рождения не гарантирует столкновения в любом случае, он просто говорит, что вероятность более 50%.
NullUserException 29.10.2012 04:13:10
@NullUserException Шанс успеха 50% (за попытку) чертовски высок: даже при 10 попытках вероятность успеха составляет 0,999. Имея это в виду и тот факт, что вы можете попробовать много в течение 24 часов, вам не нужно 34 миллиарда строк, чтобы быть уверенным, что вы угадаете хотя бы одну из них. Вот почему некоторые сессионные токены должны быть очень, очень длинными.
Pijusn 31.01.2015 10:28:30
Эти 3 однострочных кода очень полезны, я думаю ..Long.toHexString(Double.doubleToLongBits(Math.random())); UUID.randomUUID().toString(); RandomStringUtils.randomAlphanumeric(12);
Manindar 8.06.2016 07:31:33
@Pijusn Я знаю, что это старо, но ... «50% -ая вероятность» в парадоксе дня рождения - это НЕ «за попытку», а «50% -ная вероятность того, что из (в данном случае) 34 млрд. Строк существует хотя бы одна пара дубликатов ». Вам понадобится 1.6 sept illion - 1.6e21 - записей в вашей базе данных, чтобы иметь шанс 50% на попытку.
Tin Man 11.10.2017 19:21:33
30 ОТВЕТОВ
РЕШЕНИЕ

Алгоритм

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

Реализация

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

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

1534
10.12.2019 17:53:29
Если вам нужны пробелы в вашем, вы можете .replaceAll("\\d", " ");присоединиться к концу return new BigInteger(130, random).toString(32);строки, чтобы выполнить обмен регулярными выражениями. Он заменяет все цифры пробелами. Прекрасно работает для меня: я использую это вместо
weisjohn 7.10.2011 15:00:05
@ weisjohn Это хорошая идея. Вы можете сделать что-то похожее со вторым методом, удалив цифры из symbolsи используя вместо этого пробел; Вы можете контролировать среднюю длину слова, изменяя количество пробелов в символах (больше случаев для более коротких слов). Для действительно чрезмерного поддельного текстового решения вы можете использовать цепочку Маркова!
erickson 7.10.2011 16:02:33
Эти идентификаторы случайным образом выбираются из пространства определенного размера. Они могут быть длиной в 1 символ. Если вам нужна фиксированная длина, вы можете использовать второе решение с SecureRandomэкземпляром, назначенным randomпеременной.
erickson 20.12.2011 00:15:42
Почему .toString (32), а не .toString (36)?
ejain 21.02.2012 19:13:40
@ejain, потому что 32 = 2 ^ 5; каждый символ будет представлять ровно 5 битов, а 130 битов могут быть равномерно разделены на символы.
erickson 21.02.2012 21:38:01

Вот это на 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
34
3.09.2008 17:16:38
Это приведет к небезопасным последовательностям, то есть последовательностям, которые можно легко угадать.
Yuriy Nakonechnyy 3.04.2014 14:53:58
Все это случайное поколение int с двойным заражением разбито по дизайну, медленно и нечитаемо. Используйте Random#nextIntили nextLong. Переключитесь на SecureRandomесли нужно.
maaartinus 22.07.2015 01:17:11

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
812
30.08.2017 06:09:52
Помните, что это решение генерирует только случайную строку с шестнадцатеричными символами. Что может быть хорошо в некоторых случаях.
Dave 5.05.2011 09:28:17
Класс UUID полезен. Однако они не так компактны, как идентификаторы, полученные в моих ответах. Это может быть проблемой, например, в URL. Зависит от ваших потребностей.
erickson 24.08.2011 16:37:45
@Ruggs - цель - алфавитно-цифровые строки. Как с этим связано расширение вывода до любых возможных байтов?
erickson 7.10.2011 16:18:53
Согласно RFC4122 использование UUID в качестве токенов является плохой идеей: не думайте, что UUID трудно угадать; например, их не следует использовать в качестве средств защиты (идентификаторов, чье простое владение предоставляет доступ). Предсказуемый источник случайных чисел усугубит ситуацию. ietf.org/rfc/rfc4122.txt
Somatik 31.12.2012 11:31:04
UUID.randomUUID().toString().replaceAll("-", "");делает строку буквенно-цифровой, как и было запрошено.
Numid 22.01.2014 09:58:08

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

/**
 * 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
20.08.2015 06:49:20
Я не думаю, что будет справедливо провалиться на дубликаты токенов, которые основаны исключительно на вероятности.
Thom Wiggers 2.06.2012 15:22:33

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

483
18.10.2017 07:58:04
Только что просмотрели упомянутый класс из Apache Commons Lang 3.3.1библиотеки - и он использует только java.util.Randomдля обеспечения случайных последовательностей, так что производят небезопасную последовательность .
Yuriy Nakonechnyy 3.04.2014 14:51:29
Убедитесь, что вы используете 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)
Ruslans Uralovs 3.03.2015 13:28:02
НЕ ИСПОЛЬЗУЙТЕ. Это создает небезопасные последовательности !
patrickf 4.04.2019 13:03:27
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();
}
542
25.02.2016 10:41:59
+1, самое простое решение для генерации случайной строки указанной длины (кроме использования RandomStringUtils из Commons Lang).
Jonik 20.04.2012 15:49:23
Попробуйте использовать SecureRandomвместо Randomкласса. Если пароли генерируются на сервере, он может быть уязвим для атак по времени.
foens 25.06.2014 13:34:44
Я бы добавил также строчные буквы AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";и некоторые другие разрешенные символы.
ACV 7.09.2015 20:56:11
Почему бы не положить static Random rnd = new Random();внутрь метода?
Micro 8.02.2016 01:25:50
@MicroR Есть ли веская причина для создания Randomобъекта в каждом вызове метода? Я так не думаю.
cassiomolin 15.02.2016 10:49:55

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

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

    }
}
1
26.09.2017 12:18:32

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

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

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

105
29.10.2015 02:29:50
Но только 6 букв :(
Moshe Revah 11.01.2011 09:45:12
Мне это тоже помогло, но только шестнадцатеричные цифры :(
noquery 5.09.2011 05:31:46
@Zippoxer, вы могли бы согласиться с этим несколько раз =)
daniel.bavrin 17.05.2014 15:10:10
Пример OP показал следующую строку в качестве примера, AEYGF7K0DM1Xкоторый не является шестнадцатеричным. Меня беспокоит, как часто люди ошибочно принимают буквенно-цифровые и шестнадцатеричные числа. Они не одно и то же.
hfontanez 20.11.2014 02:31:59
Это гораздо менее случайно, чем нужно задавать длину строки, поскольку Math.random()выдает doubleот 0 до 1, поэтому часть экспоненты в основном не используется. Используйте random.nextLongдля случайного longвместо этого уродливого взлома.
maaartinus 22.07.2015 01:13:22

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

// "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
29.10.2015 02:30:13
Можно ли использовать SecureRandom с shuffle?
iwein 16.11.2016 10:58:23
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
20.08.2015 06:51:18

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

6
26.06.2017 22:47:13
Спасибо, исправили это. Так что по крайней мере, есть источник и ссылка действительна. С другой стороны, не похоже, что он был обновлен в течение некоторого времени, хотя я вижу, что pwgen был обновлен довольно недавно.
michaelok 26.06.2017 22:50:50
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
20.08.2015 06:50:34
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
17.04.2012 09:42:20
Я позволил себе сделать небольшие изменения. Почему вы добавляете + 0это часто? Почему вы разделяете объявление о месте и инициализации? В чем преимущество индексов 1,2,3,4 вместо 0,1,2,3? Самое главное: вы взяли случайное значение и сравнили его с 4 раза новым значением, которое всегда могло не совпадать, не получая больше случайности. Но не стесняйтесь откат.
user unknown 17.04.2012 09:50:59

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

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

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

31
2.04.2018 23:29:20
Просто имейте в виду, что есть 50% -ная вероятность того, что знак минус окажется перед результатом! Так что обертка r.nextLong () в Math.abs () может быть использована, если вы не хотите использовать знак минус: Long.toString(Math.abs(r.nextLong()), 36);
Ray Hulha 27.01.2013 02:12:03
@RayHulha: Если вам не нужен знак минус, вы должны его обрезать, потому что, как ни странно, Math.abs возвращает отрицательное значение для Long.MIN_VALUE.
user unknown 27.01.2013 13:28:49
Интересные Math.abs возвращаются отрицательно. Больше здесь: bmaurer.blogspot.co.nz/2006/10/…
Phil 10.11.2013 20:34:20
Проблема с absрешается с помощью побитового оператора для сброса наиболее значимого бита. Это будет работать для всех значений.
Radiodef 2.04.2018 23:27:35
@Radiodef Это то, что сказал @userunkown. Я полагаю, вы могли бы также сделать << 1 >>> 1.
shmosel 2.04.2018 23:35:00

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

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
28.04.2012 07:33:52

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

RandomStringUtils.randomAlphanumeric(20).toUpperCase();
106
9.12.2014 14:15:43
@kamil, я посмотрел исходный код для RandomStringUtils, и он использует экземпляр java.util.Random, созданный без аргументов. Документация для java.util.Random говорит, что она использует текущее системное время, если начальное число не предоставлено. Это означает, что его нельзя использовать для идентификаторов / ключей сеанса, так как злоумышленник может легко предсказать, что представляют собой сгенерированные идентификаторы сеанса в любой момент времени.
Inshallah 26.09.2012 10:14:26
@Inshallah: Вы (неоправданно) перерабатываете систему. Хотя я согласен с тем, что он использует время в качестве начального числа, злоумышленник должен иметь доступ к следующим данным, чтобы фактически получить то, что он хочет. 1. Время с точностью до миллисекунды, когда код был заполнен. 2. Число вызовов, которые были выполнены до настоящего времени. 3. Атомность для его собственного вызова (так что количество вызовов на данный момент остается одинаковым). Если у вашего злоумышленника есть все эти три вещи, то у вас под рукой гораздо большая проблема ...
Ajeet Ganga 13.10.2013 23:36:41
зависимость от gradle: compile 'commons-lang:commons-lang:2.6'
younes0 19.01.2015 14:35:30
@ Аджит, это не правда. Вы можете получить состояние генератора случайных чисел из его выходных данных. Если злоумышленник может сгенерировать несколько тысяч вызовов для генерации случайных токенов API, злоумышленник сможет предсказать все будущие токены API.
Thomas Grainger 20.12.2016 13:52:09
@AjeetGanga Ничего общего с инженерным делом. Если вы хотите создать идентификаторы сеанса, вам нужен криптографический генератор псевдослучайных данных. Каждый prng, использующий время в качестве начального числа, предсказуем и очень небезопасен для данных, которые должны быть непредсказуемыми. Просто используйте, SecureRandomи вы хорошо.
patrickf 19.09.2017 10:37:55

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

(for (i <- 0 until rnd.nextInt(64)) yield { 
  ('0' + rnd.nextInt(64)).asInstanceOf[Char] 
}) mkString("")
3
24.07.2012 11:11:01
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
9.10.2012 04:47:13

с помощью библиотеки apache это можно сделать в одну строку

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

вот документ http://commons.apache.org/lang/api-2.3/org/apache/commons/lang/RandomStringUtils.html

3
15.10.2012 07:52:12

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

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
16.04.2014 11:49:00
Кто-то предложил это, примерно за год до вас.
erickson 10.09.2013 04:49:58

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

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
20.08.2015 06:52:26
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
3.12.2012 06:59:05
Это в значительной степени совпадает с ответом Стива Маклеода, данным два года назад.
erickson 4.10.2013 05:40:15

Много использования 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
3.12.2012 15:16:17
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
2.04.2018 23:30:48
Эта конкатенация строк излишне неэффективна. И сумасшедший отступ делает ваш код почти нечитаемым. Это то же самое, что и идея Джейми, но плохо выполненная.
erickson 4.10.2013 05:36:49

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

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
9.01.2013 16:04:22
Кажется, в значительной степени дублировать мой ответ, который был дан два года назад.
erickson 4.10.2013 05:35:29

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

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

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

4
29.07.2013 14:07:23
Почему в мире вы используете UUID для получения случайных бит? Почему бы просто не использовать random.nextLong()? Или даже Double.doubleToLongBits(Math.random())?
erickson 4.10.2013 05:31:50
  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();
    }
8
31.07.2017 17:14:09
Это не добавляет ничего, что десятки ответов, которые были даны ранее, не охватывали. И создание нового Randomэкземпляра в каждой итерации цикла неэффективно.
erickson 10.02.2014 05:17:52

Альтернатива в 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
3.10.2018 19:09:43
Это здорово - но если вы хотите, чтобы оно было строго буквенно-цифровым (0-9, az, AZ), см. Здесьrealjava.com
Dan 23.06.2015 14:08:13

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

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();
}
0
8.12.2014 01:41: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 и символы az, нам понадобится случайное число от 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 символа (wz). Чтобы теперь сгенерировать строку определенной длины, мы можем просто использовать2^(length*numBits)-1число. Последняя проблема: если нам нужна строка определенной длины, случайное число может сгенерировать небольшое число, поэтому длина не будет достигнута, поэтому мы должны дополнить строку до требуемой длины предваряющими нулями.

12
11.03.2016 10:56:42
не могли бы вы объяснить лучше 5?
Julian Suarez 9.03.2016 16:56:27