1975 Stimmen

Wie man eine zufällige alphanumerische Zeichenfolge erzeugt

Ich habe nach einem einfach Java-Algorithmus zur Erzeugung einer pseudo-zufälligen alphanumerischen Zeichenkette. In meinem Fall würde sie als eindeutiger Sitzungs-/Schlüsselbezeichner verwendet, der "wahrscheinlich" in folgenden Fällen eindeutig ist 500K+ Generation (meine Bedürfnisse erfordern nicht wirklich etwas viel Anspruchsvolleres).

Im Idealfall könnte ich eine Länge angeben, die meinen Bedürfnissen nach Einzigartigkeit entspricht. Eine generierte Zeichenkette der Länge 12 könnte zum Beispiel wie folgt aussehen "AEYGF7K0DM1X" .

166 Stimmen

64 Stimmen

Selbst wenn man das Geburtstagsparadoxon in Betracht zieht, bräuchte man bei Verwendung von 12 alphanumerischen Zeichen (62 insgesamt) immer noch weit über 34 Milliarden Zeichenfolgen, um das Paradoxon zu erreichen. Und das Geburtstagsparadoxon garantiert sowieso keine Kollision, es sagt nur, dass die Wahrscheinlichkeit über 50 % liegt.

6 Stimmen

@NullUserException 50 % Erfolgschance (pro Versuch) ist verdammt hoch: Selbst bei 10 Versuchen liegt die Erfolgsquote bei 0,999. Wenn man das und die Tatsache bedenkt, dass man innerhalb von 24 Stunden VIELE Versuche machen kann, braucht man keine 34 Milliarden Zeichenfolgen, um ziemlich sicher zu sein, dass man mindestens eine davon errät. Das ist der Grund, warum einige Sitzungs-Tokens sehr, sehr lang sein sollten.

32voto

Michael Allen Punkte 5623

Erstaunlicherweise hat das hier niemand vorgeschlagen, aber:

import java.util.UUID

UUID.randomUUID().toString();

Einfach.

Das hat den Vorteil, dass UUIDs schön lang sind und garantiert kaum kollidieren können.

Wikipedia hat eine gute Erklärung davon:

" ... nur nach der Erzeugung von 1 Milliarde UUIDs pro Sekunde für die nächsten 100 Jahre, würde die Wahrscheinlichkeit, nur ein Duplikat zu erzeugen, etwa 50% betragen."

Die ersten vier Bits sind die Versionsart und zwei für die Variante, so dass man 122 Bits für den Zufall erhält. Wenn Sie also wollen können Sie das Ende abschneiden, um die Größe der UUID zu verringern. Es wird nicht empfohlen, aber Sie haben immer noch eine Menge Zufälligkeit, genug für Ihre 500k Datensätze leicht.

50 Stimmen

Jemand hat es vorgeschlagen, etwa ein Jahr vor Ihnen.

18voto

Howard Lovatt Punkte 950

Eine Alternative in Java 8 ist:

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

static String randomString(final int maxLength) {
  final int length = random.nextInt(maxLength + 1);
  return random.ints(length, startChar, endChar + 1)
        .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
        .toString();
}

3 Stimmen

Das ist großartig - aber wenn Sie nur alphanumerische Zeichen (0-9, a-z, A-Z) verwenden möchten, finden Sie hier rationaljava.com/2015/06/

12voto

rina Punkte 21
public static String generateSessionKey(int length){
    String alphabet =
        new String("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); // 9

    int n = alphabet.length(); // 10

    String result = new String();
    Random r = new Random(); // 11

    for (int i=0; i<length; i++) // 12
        result = result + alphabet.charAt(r.nextInt(n)); //13

    return result;
}

0 Stimmen

Eine Erklärung wäre angebracht.

11voto

Kristian Kraljic Punkte 818

Die Verwendung von UUIDs ist unsicher, da Teile der UUIDs nicht zufällig sind. Die verfahren von erickson ist sehr ordentlich, aber es erzeugt keine Zeichenketten mit gleicher Länge. Das folgende Snippet sollte ausreichend sein:

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

Warum wählen length*5 ? Nehmen wir den einfachen Fall einer zufälligen Zeichenkette der Länge 1 an, also ein zufälliges Zeichen. Um ein Zufallszeichen zu erhalten, das alle Ziffern 0-9 und die Buchstaben a-z enthält, bräuchten wir eine Zufallszahl zwischen 0 und 35, um von jedem Zeichen eines zu erhalten.

BigInteger bietet einen Konstruktor zur Erzeugung einer Zufallszahl, die gleichmäßig über den Bereich verteilt ist 0 to (2^numBits - 1) . Leider ist 35 keine Zahl, die von 2^numBits - 1 empfangen werden kann.

Wir haben also zwei Möglichkeiten: Entweder wir nehmen 2^5-1=31 o 2^6-1=63 . Wenn wir wählen würden 2^6 würden wir eine Menge "unnötiger" / "längerer" Nummern erhalten. Deshalb 2^5 ist die bessere Option, auch wenn wir vier Zeichen (w-z) verlieren. Um nun eine Zeichenkette einer bestimmten Länge zu erzeugen, können wir einfach eine 2^(length*numBits)-1 Nummer. Das letzte Problem ist, dass, wenn wir eine Zeichenkette mit einer bestimmten Länge haben wollen, der Zufallsgenerator eine kleine Zahl erzeugen könnte, so dass die Länge nicht erreicht wird, so dass wir die Zeichenkette auf die gewünschte Länge auffüllen müssen, indem wir Nullen voranstellen.

0 Stimmen

Könnten Sie die 5 besser erklären?

11voto

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

Dies fügt einfach das Passwort in die Zeichenfolge ein und... ja, es funktioniert gut. Probieren Sie es aus... Es ist sehr einfach; ich habe es geschrieben.

1 Stimmen

Ich habe mir erlaubt, einige kleine Änderungen vorzunehmen. Warum fügen Sie + 0 so oft? Warum teilt man die Deklaration von Spot und Initialisierung auf? Was ist der Vorteil der Indizes 1,2,3,4 anstelle von 0,1,2,3? Das Wichtigste: Sie haben einen Zufallswert genommen und mit if-else 4 mal einen neuen Wert verglichen, der immer falsch sein kann, ohne dass Sie mehr Zufälligkeit gewinnen. Aber Sie können gerne zurückgehen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X