Ne générant que des UUID à 8 caractères

Les bibliothèques UUID

génèrent des UUID de 32 caractères.

je veux générer des UUID à 8 caractères seulement, est-ce possible?

49
demandé sur Elouan Keryell-Even 2010-11-24 16:50:49

8 réponses

ce n'est pas possible car un UUID est un nombre de 16 octets par définition. mais bien sûr, vous pouvez générer de longues chaînes uniques de 8 caractères (voir les autres réponses).

veillez également à générer des UUIDs plus longs et à les soustraire, car certaines parties de L'ID peuvent contenir des octets fixes (par exemple, C'est le cas pour les UUIDs MAC, DCE et MD5).

42
répondu Cephalopod 2017-11-28 10:27:57

vous pouvez essayer la classe RandomStringUtils d'apache.communes :

import org.apache.commons.lang3.RandomStringUtils;

final int SHORT_ID_LENGTH = 8;

// all possible unicode characters
String shortId = RandomStringUtils.random(SHORT_UID_LENGTH);

s'il vous plaît gardez à l'esprit, qu'il contiendra tous les caractères possibles qui n'est ni URL ni human friendly.

donc vérifier d'autres méthodes aussi:

// HEX: 0-9, a-f. For example: 6587fddb, c0f182c1
shortId = RandomStringUtils.random(8, "0123456789abcdef"); 

// a-z, A-Z. For example: eRkgbzeF, MFcWSksx
shortId = RandomStringUtils.randomAlphabetic(8); 

// 0-9. For example: 76091014, 03771122
shortId = RandomStringUtils.randomNumeric(8); 

// a-z, A-Z, 0-9. For example: WRMcpIk7, s57JwCVA
shortId = RandomStringUtils.randomAlphanumeric(8); 

comme d'autres l'ont dit, la probabilité d'une collision id avec un id plus petit peut être significative. Découvrez comment problème d'anniversaire s'applique à votre cas. Vous pouvez trouver une explication agréable comment calculer approximation dans cette réponse .

19
répondu Anton Purin 2017-07-12 10:55:40

D'abord: même les identifiants uniques générés par java UUID.randomUUID ou. net GUID ne sont pas 100% uniques. Spécialement UUID.randomUUID est "seulement" une valeur aléatoire de 128 bits (sécurisée). Donc si vous le réduisez à 64 bits, 32 bits, 16 bits (ou même 1 bit) alors il devient tout simplement moins unique.

donc c'est au moins une décision basée sur le risque, combien de temps votre uuid doit être.

Deuxième: je suppose que lorsque vous parlez de "seulement 8 caractères" vous voulez dire une Chaîne de 8 normal caractères imprimables.

Si vous voulez une chaîne unique avec une longueur de 8 caractères imprimables, vous pouvez utiliser un encodage base64. Cela signifie 6bit par char, donc vous obtenez 48bit au total (possible pas très unique - mais peut-être il est ok pour votre application)

donc la voie est simple: créer un tableau aléatoire de 6 octets

 SecureRandom rand;
 // ...
 byte[] randomBytes = new byte[16];
 rand.nextBytes(randomBytes);

et ensuite le transformer en chaîne de Base64, par exemple par org.apache.commons.codec.binary.Base64

BTW: cela dépend sur votre application s'il y a une meilleure façon de créer "uuid" puis par hasard. (Si vous créez une l'Uuid qu'une seule fois par seconde, alors c'est une bonne idée d'ajouter un horodatage) (En passant: si vous combinez (xor) deux valeurs aléatoires, le résultat est toujours au moins aussi aléatoire que le plus aléatoire de la les deux).

14
répondu Ralph 2017-07-04 06:40:28

comme @Cephalopod a déclaré que ce n'est pas possible, mais vous pouvez raccourcir un UUID à 22 caractères

public static String encodeUUIDBase64(UUID uuid) {
        ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
        bb.putLong(uuid.getMostSignificantBits());
        bb.putLong(uuid.getLeastSignificantBits());
        return StringUtils.trimTrailingCharacter(BaseEncoding.base64Url().encode(bb.array()), '=');
}
2
répondu bstick12 2017-07-04 06:40:46

c'est une façon similaire que j'utilise ici pour générer un code d'erreur unique, basé sur la réponse D'Anton Purin, mais en se basant sur org.apache.commons.text.RandomStringGenerator au lieu de l'déprécié org.apache.commons.lang3.RandomStringUtils :

@Singleton
@Component
public class ErrorCodeGenerator implements Supplier<String> {

    private RandomStringGenerator errorCodeGenerator;

    public ErrorCodeGenerator() {
        errorCodeGenerator = new RandomStringGenerator.Builder()
                .withinRange('0', 'z')
                .filteredBy(t -> t >= '0' && t <= '9', t -> t >= 'A' && t <= 'Z', t -> t >= 'a' && t <= 'z')
                .build();
    }

    @Override
    public String get() {
        return errorCodeGenerator.generate(8);
    }

}

Tous les conseils sur la collision s'appliquent toujours, s'il vous plaît être conscient.

2
répondu BrunoJCM 2017-12-10 16:16:23

en fait je veux timestamp basé identificateur unique plus court, donc essayé le programme ci-dessous.

c'est une supposition avec les combinaisons nanosecond + ( endians.length * endians.length ) .

public class TimStampShorterUUID {

    private static final Character [] endians = 
           {'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', 
            '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'
            };

   private static ThreadLocal<Character> threadLocal =  new ThreadLocal<Character>();

   private static AtomicLong iterator = new AtomicLong(-1);


    public static String generateShorterTxnId() {
        // Keep this as secure random when we want more secure, in distributed systems
        int firstLetter = ThreadLocalRandom.current().nextInt(0, (endians.length));

        //Sometimes your randomness and timestamp will be same value,
        //when multiple threads are trying at the same nano second
        //time hence to differentiate it, utilize the threads requesting
        //for this value, the possible unique thread numbers == endians.length
        Character secondLetter = threadLocal.get();
        if (secondLetter == null) {
            synchronized (threadLocal) {
                if (secondLetter == null) {
                    threadLocal.set(endians[(int) (iterator.incrementAndGet() % endians.length)]);
                }
            }
            secondLetter = threadLocal.get();
        }
        return "" + endians[firstLetter] + secondLetter + System.nanoTime();
    }


    public static void main(String[] args) {

        Map<String, String> uniqueKeysTestMap = new ConcurrentHashMap<>();

        Thread t1 = new Thread() {  
            @Override
            public void run() {
                while(true) {
                    String time = generateShorterTxnId();
                    String result = uniqueKeysTestMap.put(time, "");
                    if(result != null) {
                        System.out.println("failed! - " + time);
                    }
                }
            }       
        };

        Thread t2 = new Thread() {  
            @Override
            public void run() {
                while(true) {
                    String time = generateShorterTxnId();
                    String result = uniqueKeysTestMap.put(time, "");
                    if(result != null) {
                        System.out.println("failed! - " + time);
                    }
                }
            }       
        };

        Thread t3 = new Thread() {  
            @Override
            public void run() {
                while(true) {
                    String time = generateShorterTxnId();
                    String result = uniqueKeysTestMap.put(time, "");
                    if(result != null) {
                        System.out.println("failed! - " + time);
                    }
                }
            }       
        };

        Thread t4 = new Thread() {  
            @Override
            public void run() {
                while(true) {
                    String time = generateShorterTxnId();
                    String result = uniqueKeysTestMap.put(time, "");
                    if(result != null) {
                        System.out.println("failed! - " + time);
                    }
                }
            }       
        };

        Thread t5 = new Thread() {  
            @Override
            public void run() {
                while(true) {
                    String time = generateShorterTxnId();
                    String result = uniqueKeysTestMap.put(time, "");
                    if(result != null) {
                        System.out.println("failed! - " + time);
                    }
                }
            }
        };

        Thread t6 = new Thread() {  
            @Override
            public void run() {
                while(true) {
                    String time = generateShorterTxnId();
                    String result = uniqueKeysTestMap.put(time, "");
                    if(result != null) {
                        System.out.println("failed! - " + time);
                    }
                }
            }   
        };

        Thread t7 = new Thread() {  
            @Override
            public void run() {
                while(true) {
                    String time = generateShorterTxnId();
                    String result = uniqueKeysTestMap.put(time, "");
                    if(result != null) {
                        System.out.println("failed! - " + time);
                    }
                }
            }
        };

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        t6.start();
        t7.start();
    }
}

UPDATE : ce code fonctionnera sur une seule JVM, mais nous devrions penser à une JVM distribuée, donc je pense à deux solutions l'une avec DB et l'autre sans DB.

avec DB

nom de L'entreprise (Nom abrégé 3 caractères) ---- Random_Number ---- Clé spécifique redis COMPTEUR

(3 char) ------------------------------------------------ (2 char) ---------------- (11 char)

sans DB

IPADDRESS ---- THREAD_NUMBER ---- INCR_NUMBER - - - - epoch millisecondes

(5 caractères) ----------------- (2char) ----------------------- (2 char) ----------------- (6 char)

vous mettra à jour une fois que le codage est faire.

1
répondu Kanagavelu Sugumar 2017-09-14 05:00:16

et celui-ci? En fait, ce code renvoie 13 caractères max, mais il est plus court que UUID.

import java.nio.ByteBuffer;
import java.util.UUID;

/**
 * Generate short UUID (13 characters)
 * 
 * @return short UUID
 */
public static String shortUUID() {
  UUID uuid = UUID.randomUUID();
  long l = ByteBuffer.wrap(uuid.toString().getBytes()).getLong();
  return Long.toString(l, Character.MAX_RADIX);
}
-1
répondu sanghoon2 2013-06-19 05:06:38

je ne pense pas que c'est possible, mais vous avez une bonne solution.

  1. couper l'extrémité de votre UUID en utilisant le substrat ()
  2. code d'utilisation new Random(System.currentTimeMillis()).nextInt(99999999); cela générera des identifiants aléatoires jusqu'à 8 caractères de long.
  3. générer de l'identification alphanumérique:

    char[] chars = "abcdefghijklmnopqrstuvwxyzABSDEFGHIJKLMNOPQRSTUVWXYZ1234567890".toCharArray();
    Random r = new Random(System.currentTimeMillis());
    char[] id = new char[8];
    for (int i = 0;  i < 8;  i++) {
        id[i] = chars[r.nextInt(chars.length)];
    }
    return new String(id);
    
-12
répondu AlexR 2010-11-24 14:02:28