Jak wygenerować losowy ciąg alfanumeryczny

Szukałem prostego algorytmu Javy do generowania pseudolosowego ciągu alfanumerycznego. W mojej sytuacji byłby on używany jako unikalny identyfikator sesji / klucza, który "prawdopodobnie" byłby unikalny przez generowanie 500K+ (moje potrzeby tak naprawdę nie wymagają niczego bardziej wyszukanego).

Idealnie, byłbym w stanie określić długość w zależności od moich potrzeb unikalności. Na przykład, wygenerowany ciąg o długości 12 może wyglądać jak "AEYGF7K0DM1X".

Author: Todd, 2008-09-03

30 answers

Algorytm

Aby wygenerować losowy ciąg znaków, połącz znaki losowane losowo z zestawu akceptowalnych symboli, aż ciąg osiągnie żądaną długość.

Implementacja

Oto dość prosty i bardzo elastyczny kod do generowania losowych identyfikatorów. przeczytaj następujące informacje , aby uzyskać ważne uwagi dotyczące aplikacji.

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

}

Przykłady użycia

Tworzenie niepewnego generatora dla 8-znakowego "identyfikator": {]}

RandomString gen = new RandomString(8, ThreadLocalRandom.current());

Utwórz Bezpieczny generator identyfikatorów sesji:

RandomString session = new RandomString();

Utwórz generator z łatwymi do odczytania kodami do drukowania. Ciągi są dłuższe niż pełne ciągi alfanumeryczne, aby zrekompensować użycie mniejszej liczby symboli:

String easy = RandomString.digits + "ACEFGHJKLMNPQRUVWXYabcdefhijkprstuvwx";
RandomString tickets = new RandomString(23, new SecureRandom(), easy);

Użyj jako identyfikatory sesji

Generowanie identyfikatorów sesji, które mogą być unikalne, nie jest wystarczająco dobre, lub można po prostu użyć prostego licznika. Atakujący przejmują sesje, gdy przewidywalne identyfikatory są używany.

Istnieje napięcie między długością a bezpieczeństwem. Krótsze identyfikatory są łatwiejsze do odgadnięcia, ponieważ możliwości jest mniej. Jednak dłuższe identyfikatory zużywają więcej pamięci masowej i przepustowości. Większy zestaw symboli pomaga, ale może powodować problemy z kodowaniem, jeśli identyfikatory są dołączane do adresów URL lub ponownie wprowadzane ręcznie. Źródło losowości lub entropii dla identyfikatorów sesji powinno pochodzić z generatora liczb losowych zaprojektowanego do kryptografii. Jednakże, inicjalizacja tych generatorów może być czasami kosztowna obliczeniowo lub powolna, więc należy podjąć wysiłek, aby ponownie je wykorzystać, gdy jest to możliwe.

Użyj jako identyfikatory obiektów

Nie każda aplikacja wymaga bezpieczeństwa. Przypisanie losowe może być skutecznym sposobem generowania identyfikatorów przez wiele jednostek we współdzielonej przestrzeni bez jakiejkolwiek koordynacji lub partycjonowania. Koordynacja może być powolna, szczególnie w środowisku klastrowym lub rozproszonym, a rozdzielenie przestrzeni powoduje problemy gdy podmioty kończą z udziałami, które są zbyt małe lub zbyt duże.

Identyfikatory generowane bez podejmowania środków w celu uczynienia ich nieprzewidywalnymi powinny być chronione w inny sposób, Jeśli atakujący może je przeglądać i manipulować, jak to ma miejsce w większości aplikacji internetowych. Powinien istnieć oddzielny system autoryzacji, który chroni obiekty, których identyfikator może odgadnąć atakujący bez uprawnień dostępu.

Należy również zwrócić uwagę na używanie identyfikatorów, które są długie wystarczająco, aby kolizje były mało prawdopodobne, biorąc pod uwagę przewidywaną całkowitą liczbę identyfikatorów. Jest to określane jako " paradoks urodzinowy."prawdopodobieństwo kolizji, p , wynosi w przybliżeniu n2/(2q x), gdzie n jest liczbą faktycznie wygenerowanych identyfikatorów, q jest liczbą odrębnych symboli w alfabecie, a x jest długością identyfikatorów. Powinna to być bardzo mała liczba, jak 2-50 lub mniej.

Wypracowanie tego pokazuje, że szansa kolizji pomiędzy 500K 15-znakowymi identyfikatorami wynosi ok. 2-52, co jest prawdopodobnie mniej prawdopodobne niż niewykryte błędy z promieniowania kosmicznego, itp.

Porównanie z uuid

Zgodnie z ich specyfikacją, uuid nie są zaprojektowane tak, aby były nieprzewidywalne i nie powinny być używane jako identyfikatory sesji.

Uuid w standardowym formacie zajmują dużo miejsca: 36 znaków na 122 bity Entropia. (Nie wszystkie bity "losowego" identyfikatora UUID są wybierane losowo.) Losowo wybrany ciąg alfanumeryczny zawiera więcej entropii w zaledwie 21 znakach.

Uuid nie są elastyczne; mają ustandaryzowaną strukturę i układ. To jest ich główna cnota, jak również ich główna słabość. Przy współpracy ze stroną zewnętrzną pomocna może być standaryzacja oferowana przez uuid. Do użytku wyłącznie wewnętrznego mogą być nieefektywne.

 1572
Author: erickson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-12-10 17:53:29

Java dostarcza sposobu, aby to zrobić bezpośrednio. Jeśli nie chcesz kresek, łatwo je rozebrać. Wystarczy użyć 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;
    }
}

Wyjście

uuid = 2d7428a6-b58c-4008-8575-f05549f16316
 839
Author: Steve McLeod,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 16:52:15
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();
}
 583
Author: maxp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 16:57:45

Jeśli chcesz używać klas Apache, możesz użyć org.apache.commons.text.RandomStringGenerator (Apache Commons Text ).

Przykład:

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

Od Apache Commons Lang 3.6, RandomStringUtils jest przestarzały.

 491
Author: numéro6,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 16:57:03

Możesz użyć biblioteki Apache Commons do tego, Randomstringuls :

RandomStringUtils.randomAlphanumeric(20).toUpperCase();
 117
Author: manish_s,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 17:07:22

W jednym wierszu:

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

Źródło: Java-generowanie losowego ciągu

 107
Author: 4 revs, 4 users 59%anonymous,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 17:01:11

Jest to łatwe do osiągnięcia bez żadnych zewnętrznych bibliotek.

1. Cryptographic Pseudo Random Data Generation (PRNG)

Najpierw potrzebujesz kryptograficznego PRNG. Java ma SecureRandom do tego i zazwyczaj używa najlepszego źródła entropii na maszynie (np. /dev/random). Czytaj więcej tutaj .

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

Uwaga: SecureRandom jest najwolniejszym, ale najbezpieczniejszym sposobem generowania losowych bajtów w Javie. Polecam jednak Nie biorąc pod uwagę wydajność tutaj, ponieważ zwykle nie ma realnego wpływu na Twoją aplikację, chyba że musisz wygenerować miliony tokenów na sekundę.

2. Wymagana przestrzeń możliwych wartości

Następnie musisz zdecydować, "jak wyjątkowy" musi być twój żeton. Jedynym punktem rozważania entropii jest upewnienie się, że system jest w stanie oprzeć się atakom brute force: przestrzeń możliwych wartości musi być tak duża, że każdy atakujący może spróbować tylko znikomej części wartości w czas bezsensowny1.

Unikalne identyfikatory, takie jak losowe UUID mieć 122 bit entropii (tj. 2^122 = 5.3x10^36) - szansa kolizji wynosi" *(...) aby istnieje jedna na miliard szans na powielenie, należy wygenerować 103 biliony uuid wersji 42". wybierzemy 128 bitów, ponieważ pasuje dokładnie do 16 bajtów i jest postrzegany jako wysoce wystarczający, aby być unikalny dla praktycznie każdego, ale najbardziej ekstremalne, przypadki użycia i nie musisz myśleć o duplikatach. Oto prosta tabela porównawcza entropii zawierająca prostą analizę problemu urodzinowego .

Porównanie rozmiarów tokenów

dla prostych wymagań, długość 8 lub 12 bajtów może wystarczyć, ale z 16 bajtami jesteś po "bezpiecznej stronie".

I to w zasadzie wszystko. Ostatnią rzeczą jest myślenie o kodowaniu, aby można było przedstawić go jako tekst drukowany(read, a String).

3. Binary do kodowania tekstu

Typowe kodowania to:

  • Base64 każdy znak koduje 6 bitów, tworząc narzut 33%. Na szczęście istnieją standardowe implementacje w Java 8+ i Android . Ze starszą wersją Javy można korzystać z dowolnej z licznych bibliotek stron trzecich . Jeśli chcesz, aby Twoje tokeny były bezpieczne dla URL użyj URL-safe wersja RFC4648 (która zwykle jest obsługiwana przez większość implementacji). Przykładowe kodowanie 16 bajty z wypełnieniem: XfJhfv3C0P6ag7y9VQxSbw==

  • Base32 każdy znak koduje 5 bitów, tworząc 40% narzutu. Będzie to Używać A-Z i 2-7, dzięki czemu jest to oszczędne miejsce, a jednocześnie nie rozróżnia wielkości liter. Nie ma żadnej standardowej implementacji w JDK. Przykład kodowania 16 bajtów bez wypełnienia: WUPIL5DQTZGMF4D3NX5L7LNFOY

  • Base16 (szesnastkowy) każdy znak koduje cztery bity, wymagając dwóch znaków na bajt (tj. bajty tworzą łańcuch o długości 32). Dlatego szesnastkowy jest mniej wydajny niż Base32, ale jest bezpieczny w użyciu w większości przypadków (URL), ponieważ używa tylko 0-9 i A do F. Przykład kodowania 16 bajtów: 4fa3dd0f57cb3bf331441ed285b27735. Zobacz dyskusję o przepełnieniu stosu na temat konwersji do systemu szesnastkowego tutaj .

Dodatkowe kodowania, takie jak Base85 i egzotyczne Base122 istnieją z lepszą/gorszą wydajnością przestrzeni. Możesz stworzyć własne kodowanie (które zasadniczo większość odpowiedzi w tym wątku ma), ale odradzam, jeśli nie masz bardzo konkretnych wymagań. Zobacz więcej schematów kodowania w artykule w Wikipedii .

4. Podsumowanie i przykład

  • użycie SecureRandom
  • Użyj co najmniej 16 bajtów (2^128) możliwych wartości
  • Koduj zgodnie z Twoimi wymaganiami (Zwykle hex lub base32 jeśli potrzebujesz, aby był alfanumeryczny)

Nie

  • ... użyj kodowania home brew: lepiej utrzymywalne i czytelne dla innych, jeśli zobaczą, jakiego standardowego kodowania używasz zamiast dziwnych dla pętli tworzących znaki na raz.
  • ... uuid: nie ma gwarancji na losowość; marnujesz 6 bitów entropii i masz verbose string representation

Przykład: Generator Heksadecymalny

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); // Hexadecimal encoding
}

//generateRandomHexToken(16) -> 2189df7475e96aa3982dbeab266497cd
Na przykład: Base64 Token Generator (URL Safe)
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

Przykład: Java Cli Tool

Jeśli chcesz mieć gotowe do użycia narzędzie CLI możesz użyć kości :

Przykład: powiązany problem-Chroń swoje bieżące identyfikatory

Jeśli masz już identyfikator, którego możesz użyć (np. syntetyczny long w encji), ale nie chcesz publikować wewnętrznej wartości, możesz użyć tej biblioteki do zaszyfrowania go i zaciemnienia: https://github.com/patrickfav/id-mask

IdMask<Long> idMask = IdMasks.forLongIds(Config.builder(key).build());
String maskedId = idMask.mask(id);
// Example: NPSBolhMyabUBdTyanrbqT8
long originalId = idMask.unmask(maskedId);
 83
Author: Patrick Favre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 16:30:23

Użycie dolara powinno być tak proste jak:

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

Wypisuje coś takiego:

DKL1SBH9UJWC
JH7P0IT21EA5
5DTI72EO6SFU
HQUMJTEBNF7Y
1HCR6SKYWGT7
 42
Author: dfa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 15:38:41

Tutaj jest w Javie:

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

Oto przykładowy przebieg:

scala> RandomAlphaNum.gen(42)
res3: java.lang.String = uja6snx21bswf9t89s00bxssu8g6qlu16ffzqaxxoy
 36
Author: Apocalisp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-03 17:16:38

Krótkie i łatwe rozwiązanie, ale używa tylko małych liter i cyfr:

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

Rozmiar jest około 12 cyfr do bazy 36 i nie można go poprawić dalej, w ten sposób. Oczywiście można dołączyć wiele instancji.

 32
Author: user unknown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 15:45:35

Zaskakujące, nikt tu tego nie zasugerował, ale:

import java.util.UUID

UUID.randomUUID().toString();
Spokojnie. Zaletą tego jest to, że UUIDs są ładne, długie i gwarantowane, że będą prawie niemożliwe do zderzenia.

Wikipedia ma dobre wyjaśnienie tego:

" ...dopiero po wygenerowaniu 1 miliarda uuid co sekundę przez następne 100 lat prawdopodobieństwo utworzenia tylko jednego duplikatu wyniosłoby około 50%."

Pierwsze cztery bity to typ wersji i dwa dla wariantu, więc ty zdobądź 122 bity losowe. Więc jeśli chcesz , możesz obciąć od końca, aby zmniejszyć rozmiar UUID. Nie jest to zalecane, ale nadal masz mnóstwo losowości, wystarczy na twoje rekordy 500K łatwe.

 31
Author: Michael Allen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 15:57:14

Alternatywą w Javie 8 jest:

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();
}
 17
Author: Howard Lovatt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-03 19:09:43

Używanie uuid jest niebezpieczne, ponieważ części UUID nie są w ogóle przypadkowe. procedura Ericksona jest bardzo zgrabna, ale nie tworzy ciągów o tej samej długości. Poniższy fragment powinien być wystarczający:

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

Dlaczego wybrać length*5? Załóżmy prosty przypadek losowego ciągu o długości 1, więc jeden losowy znak. Aby otrzymać losowy znak zawierający wszystkie cyfry 0-9 i znaki a-z, potrzebowalibyśmy losowej liczby z zakresu od 0 do 35, aby uzyskać po jednym z każdego charakter.

BigInteger dostarcza konstruktor do generowania liczby losowej, równomiernie rozłożonej w zakresie 0 to (2^numBits - 1). Niestety 35 nie jest liczbą, którą można otrzymać przez 2 ^ numBits - 1.

Więc mamy dwie opcje: albo iść z 2^5-1=31 lub 2^6-1=63. Jeśli wybierzemy 2^6 otrzymamy dużo "niepotrzebnych" / "dłuższych" liczb. Dlatego 2^5 jest lepszym rozwiązaniem, nawet jeśli stracimy cztery znaki (w-z). Aby teraz wygenerować ciąg o określonej długości, możemy po prostu użyć 2^(length*numBits)-1 numer. Ostatni problem, jeśli chcemy ciąg o określonej długości, random może wygenerować małą liczbę, więc długość nie jest spełniona, więc musimy ustawić ciąg do wymaganej długości poprzedzającej zera.

 12
Author: Kristian Kraljic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 16:16:44
import java.util.Random;

public class passGen{
    // Version 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 StringBuilder pass = new StringBuilder();

    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(26);
                pass.append(dCase.charAt(spot));
            } else if (rPick == 1) {
                int spot = r.nextInt(26);
                pass.append(uCase.charAt(spot));
            } else if (rPick == 2) {
                int spot = r.nextInt(8);
                pass.append(sChar.charAt(spot));
            } else {
                int spot = r.nextInt(10);
                pass.append(intChar.charAt(spot));
            }
        }
        System.out.println ("Generated Pass: " + pass.toString());
    }
}

To po prostu dodaje hasło do łańcucha i... tak, działa dobrze. Zobacz też.. To bardzo proste, ja to napisałem.

 11
Author: cmpbah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 15:42:30
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
Author: rina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 15:48:15

Znalazłem rozwiązanie, które generuje losowy łańcuch zakodowany szesnastkowo. Dostarczony test jednostkowy zdaje się pasować do mojego podstawowego przypadku użycia. Chociaż jest to nieco bardziej złożone niż niektóre z innych udzielonych odpowiedzi.

/**
 * 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);
        }
    }
}
 9
Author: Todd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-20 06:49:20
  1. Zmień ciąg znaków zgodnie z Twoimi wymaganiami.

  2. Ciąg jest niezmienny. Tutaj StringBuilder.append jest bardziej wydajne niż łączenie łańcuchów.


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
Author: deepakmodak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 16:08:25

Nie podoba mi się żadna z tych odpowiedzi dotyczących "prostego" rozwiązania: S

Wybrałbym prosty;), czysty Java, jeden liner (Entropia opiera się na losowej długości łańcucha i podanym zestawie znaków):

public String randomString(int length, String characterSet) {
    return IntStream.range(0, length).map(i -> new SecureRandom().nextInt(characterSet.length())).mapToObj(randomInt -> characterSet.substring(randomInt, randomInt + 1)).collect(Collectors.joining());
}

@Test
public void buildFiveRandomStrings() {
    for (int q = 0; q < 5; q++) {
        System.out.println(randomString(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")); // The character set can basically be anything
    }
}

Lub (nieco bardziej czytelny stary sposób)

public String randomString(int length, String characterSet) {
    StringBuilder sb = new StringBuilder(); // Consider using StringBuffer if needed
    for (int i = 0; i < length; i++) {
        int randomInt = new SecureRandom().nextInt(characterSet.length());
        sb.append(characterSet.substring(randomInt, randomInt + 1));
    }
    return sb.toString();
}

@Test
public void buildFiveRandomStrings() {
    for (int q = 0; q < 5; q++) {
        System.out.println(randomString(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")); // The character set can basically be anything
    }
}

Ale z drugiej strony można też wybrać UUID , który ma całkiem dobrą entropię:

UUID.randomUUID().toString().replace("-", "")
 8
Author: Patrik Bego,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 16:39:21

Używam biblioteki z Apache Commons aby wygenerować ciąg alfanumeryczny:

import org.apache.commons.lang3.RandomStringUtils;

String keyLength = 20;
RandomStringUtils.randomAlphanumeric(keylength);
To szybkie i proste!
 8
Author: Chuong Tran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 16:46:56
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
Author: Jameskittu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-20 06:50:34
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
Author: Suganya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 17:05:10

Mówisz "proste", ale na wypadek, gdyby ktoś jeszcze szukał czegoś, co spełnia bardziej rygorystyczne wymagania bezpieczeństwa, możesz rzucić okiem na jpwgen . jpwgen jest wzorowany na pwgen w Uniksie i jest bardzo konfigurowalny.

 6
Author: michaelok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-26 22:47:13

Możesz użyć następującego kodu, jeśli hasło obowiązkowe zawiera cyfry i Alfabetyczne znaki specjalne:

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
Author: Prasobh.Kollattu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 15:59:23

Możesz użyć klasy uuid z Komunikatem getLeastSignificantBits (), aby uzyskać 64-bitowe dane random , a następnie przekonwertować je na liczbę radix 36 (tzn. łańcuch składający się z 0-9,A-Z):

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

Daje to łańcuch o długości do 13 znaków. Używamy matematyki.abs (), aby upewnić się, że nie ma znaku minus.

 4
Author: neuhaus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 16:06:57

Oto jednolinijkowy przez AbacusUtil :

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

Random nie oznacza, że musi być unikalny. Aby uzyskać unikalne ciągi, użyj:

N.uuid() // E.g.: "e812e749-cf4c-4959-8ee1-57829a69a80f". length is 36.
N.guid() // E.g.: "0678ce04e18945559ba82ddeccaabfcd". length is 32 without '-'
 4
Author: user_3380739,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 16:21:17

Myślę, że jest to najmniejsze rozwiązanie tutaj, lub prawie jedno z najmniejszych:

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

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

    return randomString;
}

Kod działa dobrze. Jeśli używasz tej metody, zalecam użycie więcej niż 10 znaków. Kolizja dzieje się na 5 znaków / 30362 iteracji. Trwało to 9 sekund.

 4
Author: FileInputStream,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 16:41:23

Oto rozwiązanie Scali:

(for (i <- 0 until rnd.nextInt(64)) yield { 
  ('0' + rnd.nextInt(64)).asInstanceOf[Char] 
}) mkString("")
 3
Author: Ugo Matrangolo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-24 11:11:01

Używając biblioteki Apache Commons , można to zrobić w jednej linii:

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

Dokumentacja

 3
Author: hridayesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 15:52:28
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
Author: duggu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 16:03:27
public static String getRandomString(int length) {
    char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST".toCharArray();

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

    return randomStr;
}
 3
Author: Prasad Parab,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-12 16:40:46