java stringhe - Come generare una stringa alfanumerica casuale?



random caratteri (25)

Stavo cercando un semplice algoritmo Java per generare una stringa alfanumerica pseudo-casuale. Nella mia situazione verrebbe utilizzato come identificatore di sessione / chiave univoco che "verosimilmente" sarebbe unico oltre la generazione di 500K + (le mie esigenze non richiedono in realtà nulla di molto più sofisticato). Idealmente, sarei in grado di specificare una lunghezza a seconda delle mie esigenze di unicità. Ad esempio, una stringa generata di lunghezza 12 potrebbe sembrare qualcosa come "AEYGF7K0DM1X" .


Answers

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

Java fornisce un modo per farlo direttamente. Se non vuoi i trattini, sono facili da togliere. Basta usare 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;
    }
}

Produzione:

uuid = 2d7428a6-b58c-4008-8575-f05549f16316

Puoi utilizzare la classe UUID con il suo messaggio getLeastSignificantBits () per ottenere 64 bit di dati casuali, quindi convertirli in un numero radix 36 (cioè una stringa composta da 0-9, AZ):

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

Questo produce una stringa lunga fino a 13 caratteri. Usiamo Math.abs () per assicurarci che non ci sia un segno meno nascosto dentro.


Ecco il codice di una riga di AbacusUtil

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

Casuale non significa che deve essere unico. per ottenere stringhe univoche, usando:

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

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 = "[email protected]#$%^&*";
    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);
    }
}

Quindi, ciò che fa è solo aggiungere la password nella stringa e ... sì, funziona bene, controlla ... molto semplice. l'ho scritto io


L'utilizzo degli UUID non è sicuro, in quanto parti dell'UUID non sono affatto casuali. La procedura di @erickson è molto accurata, ma non crea stringhe della stessa lunghezza. Il seguente frammento di codice dovrebbe essere sufficiente:

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

Perché scegliere la length*5 . Assumiamo il caso semplice di una stringa casuale di lunghezza 1, quindi un carattere casuale. Per ottenere un carattere casuale contenente tutte le cifre 0-9 e i caratteri az, avremmo bisogno di un numero casuale compreso tra 0 e 35 per ottenere uno di ciascun carattere. BigInteger fornisce un costruttore per generare un numero casuale, distribuito uniformemente nell'intervallo da 0 to (2^numBits - 1) . Purtroppo 35 non è un numero che può essere ricevuto da 2 ^ numBits - 1. Quindi abbiamo due opzioni: O vai con 2^5-1=31 o 2^6-1=63 . Se avessimo scelto 2^6 avremmo molti numeri "inutili" / "più lunghi". Quindi 2^5 è l'opzione migliore, anche se perdiamo 4 caratteri (wz). Per generare una stringa di una certa lunghezza, possiamo semplicemente usare un numero 2^(length*numBits)-1 . L'ultimo problema, se vogliamo una stringa con una certa lunghezza, random potrebbe generare un piccolo numero, quindi la lunghezza non è soddisfatta, quindi dobbiamo applicare la stringa alla lunghezza richiesta in anticipo di zero.


Questo è facilmente realizzabile senza alcuna libreria esterna.

1. Generazione di dati pseudo casuali crittografici

Per prima cosa hai bisogno di un PRNG crittografico. Java ha SecureRandom perché generalmente utilizza la migliore fonte di entropia sulla macchina (ad es. /dev/random ). Leggi di più qui.

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

Nota: SecureRandom è il modo più lento ma più sicuro in Java di generare byte casuali. Tuttavia, consiglio di NON considerare le prestazioni qui poiché di solito non ha alcun impatto reale sulla tua applicazione, a meno che tu non debba generare milioni di token al secondo.

2. Spazio richiesto dei valori possibili

Quindi devi decidere "quanto è unico" il tuo token deve essere. L'unico e unico punto di considerare l'entropia è assicurarsi che il sistema possa resistere agli attacchi di forza bruta: lo spazio dei valori possibili deve essere così grande che qualsiasi attaccante possa provare solo una proporzione trascurabile dei valori in un tempo non ridicolo 1 . Identificatori univoci come UUID casuale hanno 122 bit di entropia (cioè 2 ^ 122 = 5.3x10 ^ 36) - la possibilità di collisione è "* (...) perché ci sia una possibilità su un miliardo di duplicati, 103 trilioni gli UUID versione 4 devono essere generati 2 ". Scegliamo 128 bit poiché si adatta esattamente a 16 byte ed è visto come altamente sufficiente per essere unici per praticamente tutti, ma i casi di utilizzo più estremi e non devi pensare ai duplicati. Ecco una semplice tabella di confronto dell'entropia che include l'analisi semplice del problema del compleanno .

Per requisiti semplici, potrebbe essere sufficiente una lunghezza di 8 o 12 byte, ma con 16 byte ci si trova nella "parte sicura".

E questo è fondamentalmente. L'ultima cosa è pensare alla codifica in modo che possa essere rappresentata come un testo stampabile (leggi, una String ).

3. Codifica da binario a testo

Le codifiche tipiche includono:

  • Base64 ogni personaggio codifica a 6 bit creando un overhead del 33%. Sfortunatamente non vi è alcuna implementazione standard nel JDK ( 7 e seguenti - c'è in Android e Java 8+ ). Ma esistono numerose librerie che aggiungono questo. Lo svantaggio è che Base64 standard non è sicuro per es. urls e come nome file nella maggior parte dei file system che richiedono una codifica aggiuntiva (ad esempio la codifica url ) o la versione sicura per URL di Base64 . Esempio di codifica di 16 byte con padding: XfJhfv3C0P6ag7y9VQxSbw==

  • Base32 ogni personaggio codifica a 5 bit creando un overhead del 40%. Questo utilizzerà AZ e 2-7 che lo rendono ragionevolmente efficiente nello spazio pur essendo alfanumerico senza distinzione tra maiuscole e minuscole. Non esiste un'implementazione standard nel JDK . Esempio di codifica di 16 byte senza padding: WUPIL5DQTZGMF4D3NX5L7LNFOY

  • Base16 (hex) ogni carattere codifica a 4 bit richiedendo 2 caratteri per byte (cioè 16 byte creano una stringa di lunghezza 32). Quindi hex è meno efficiente di Base32 ma è sicuro da usare nella maggior parte dei casi (url) poiché usa solo 0-9 e A a F Esempio di codifica di 16 byte: 4fa3dd0f57cb3bf331441ed285b27735 . Vedi una discussione SO sulla conversione in esadecimale qui.

Codifiche aggiuntive come Base85 e l'esotico Base122 esistono con un'efficienza dello spazio migliore / peggiore. È possibile creare la propria codifica (che praticamente la maggior parte delle risposte in questo thread fa) ma vorrei sconsigliarla, se non si hanno requisiti molto specifici. Vedi più schemi di codifica nell'articolo di Wikipedia.

4. Riepilogo ed esempio

  • Usa SecureRandom
  • Utilizzare almeno 16 byte (2 ^ 128) di valori possibili
  • Codifica in base alle tue esigenze (in genere hex o base32 se ne hai bisogno per essere alfanumerico)

non

  • ... usa la codifica brew della tua casa: meglio mantenibile e leggibile per gli altri se vedono quale codifica standard usi invece di strana per i loop che creano caratteri alla volta.
  • ... usa UUID: stai sprecando 6 bit di entropia e hai una rappresentazione di stringa dettagliata

Esempio: generatore di token esadecimali

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

Esempio: strumento

Se vuoi uno strumento cli pronto all'uso, puoi usare i dadi: https://github.com/patrickfav/dice


Una soluzione breve e facile, ma utilizza solo caratteri minuscoli e numerici:

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

La dimensione è di circa 12 cifre rispetto alla base 36 e non può essere ulteriormente migliorata in questo modo. Ovviamente puoi aggiungere più istanze.


Miglior metodo casuale generatore di stringhe

public class RandomStringGenerator{

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

}

È possibile utilizzare la libreria Apache per questo: RandomStringUtils

RandomStringUtils.randomAlphanumeric(20).toUpperCase();


Si parla di "semplice", ma nel caso in cui qualcun altro stia cercando qualcosa che soddisfi requisiti di sicurezza più stringenti, si potrebbe voler dare un'occhiata a jpwgen . jpwgen è modellato su pwgen in Unix ed è molto configurabile.


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

Ho trovato questa soluzione che genera una stringa esadecimale casuale codificata. Il test dell'unità fornito sembra confermare il mio caso d'uso principale. Anche se, è leggermente più complesso di alcune delle altre risposte fornite.

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

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

Ecco un esempio di esecuzione:

scala> RandomAlphaNum.gen(42)
res3: java.lang.String = uja6snx21bswf9t89s00bxssu8g6qlu16ffzqaxxoy

Un'alternativa in 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();
}

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

Forse questo è utile

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="[email protected]#$%^&*()_+-=.,/';:?><~*/-+";
        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;

    }
}

Se sei felice di utilizzare le classi Apache, puoi utilizzare org.apache.commons.text.RandomStringGenerator (commons-text).

Esempio:

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

Poiché commons-lang 3.6, RandomStringUtils è deprecato.


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

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

        return randomStr;
    }

  1. Cambia i caratteri della stringa secondo i tuoi requisiti.

  2. La stringa è immutabile. Qui StringBuilder.append è più efficiente della concatenazione di stringhe.


public static String getRandomString(int length) {
       final String characters = "[email protected]#$%^&*()_+";
       StringBuilder result = new StringBuilder();
       while(length > 0) {
           Random rand = new Random();
           result.append(characters.charAt(rand.nextInt(characters.length())));
           length--;
       }
       return result.toString();
    }

Ecco una soluzione Scala:

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


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

 rand.nextInt((max+1) - min) + min;




java string random alphanumeric