Reputation: 14727
Each video at YouTube has a unique identifying string such as 1cru2fzUlEc.
Is any Java way of generating something close to it? By close I mean the string is unique, short, and uses numbers and letters (case-sensitive).
I need to use such a string in the same way YouTube uses: identify a record in the backend system. I am doing a Java web application. I don't want to use the approach of http://example.com?id=123.
I know Java's UUID implementation can produce similar results, but it is too long compared to what YouTube has.
Thanks!
Thanks so much to you all for your replies. All your input is USEFUL! It appears that there is no perfect solution. Anything perfect (if not UUID) must generate and check (to avoid duplicates). Am I right?
Can I safely say that YouTube faces the same issues when generating its own 12-character video string as we Java people do?
Cheers!
I would like to use full range of alphanumeric characters and not just hexadecimal digits. I am going to use the solution from Marcus Junius Brutus. I feel it is intuitive and safely enough. Theoretically I will have to check each generated string, but I am not going to, because each check is another database call. I am going to add unique constraint to the table field for the generated string ID. I am going to let that unlucky user to fail maybe the first time he generates a record. What he needs to do is to go back to the form fill it again and save it (hopefully not fail second time due to repeated string values). Initially I am going to use 12-char string and I can increase the length easily when there is a need.
I am going to use this solution for a distributed web application talking to the same backend database, which means multiple JVMs for the same application.
Here is my solution and I hope it will work.
String sampleAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
char[] buf = new char[12];
for (int i = 0 ; i < 12 ; i++)
buf[i] = sampleAlphabet.charAt(random.nextInt(sampleAlphabet.length()));
return new String(buf);
Thank you all for your responses. They are all acceptable solutions.I really appreciate it.
Best to you all!
Upvotes: 4
Views: 4619
Reputation: 449
to generate a Random character use this function
public static String generateKey(int length) {
String alphabet
= new String("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); //9
int n = alphabet.length();
String result = new String();
Random r = new Random();
for (int i = 0; i < length; i++) {
result = result + alphabet.charAt(r.nextInt(n));
}
return result;
}
Upvotes: 1
Reputation: 78
Why don't you try this? It satisfies all your needs.
https://github.com/peet/hashids.java
Upvotes: 5
Reputation: 27286
If you want to generate arbitrary characters (e.g. the full range of alphanumerics and not just hexadecimal digits) or even tamper with their frequency, create an array with the sample characters you want and then:
String sampleAlphabet = "whatever";
Random random = new Random();
char[] bf = new char[length];
for (int i = 0 ; i < length ; i++)
buf[i] = sampleAlphabet.charAt(random.nextInt(sampleAlphabet.length());
return new String(bf);
Use a SecureRandom, if you like, for extra safety.
Upvotes: 1
Reputation: 234847
A UUID is a hex representation of a 128-bit value (with "-" inserted as punctuation, much as commas or spaces are used as thousands separators in decimal representations). You can preserve the benefits of a UUID and shorten the identifier by generating a UUID as usual and then converting the 128-bit value to a more compact representation such as Base64 or Ascii85 (a.k.a. Base85). That would bring it down to 20 characters (using Ascii85); not quite as compact as YouTube's ids but a considerable savings from the 36 characters of a UUID.
If that's still too long, generate a smaller number of random bytes (using a good PRNG) and convert to Ascii85. Every four bytes of data generates 5 characters in Ascii85.
EDIT: In an earlier comment, I suggested using a hash of a UUID. Here's how it would work.
Upvotes: 2
Reputation: 7322
Well UUID is usually a 128-bit number formatted in hexadecimal base.
Well largest 128-bit number is 2^128-12
. If presented in hexadecimal base will become 32 digits characters length log(2^128)/log(16) = 32
You can define a custom base, (for example containing 0-9, a-z and A-Z) which will become base (62) 10+26+26 (in this base digits are case sensitive!).
So largest 128-bit number will become ceil(log(2^128)/log(62)) = 22
digits length.
If it is still large, then you shall use a smaller number (not a 128 bit one).
Upvotes: 1
Reputation: 11117
The best way I think is to generate a random string with numbers and letters and before using it, make sure it does not exist in your database. If it does, just generate another one and check again, etc...
It's most unlikely that you will generate the same string twice (but possible).
Or as you said you can use Java's UUID implementation, but it's a bit long I guess.
Upvotes: 3
Reputation: 16403
You could Base64 encode the current time in ms since the epoch:
byte[] bytes = String.valueOf(System.currentTimeMillis()).getBytes();
String s = new sun.misc.BASE64Encoder().encode(bytes);
See https://ideone.com/f4cFy1 for a demo.
Upvotes: 2
Reputation: 3341
Here's a nice method to do what you want. length
is the length of the UUID you want. It's important to note that as you shorten the length of the UUID, the chance of collision increases (thanks assylias for mentioning this in the comments). You should definitely be checking to make sure that it doesn't already exist in the database before using it. If it does, then just generate another.
public String getUUID(int length)
{
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, length);
}
Upvotes: 0