Kaip sukurti atsitiktinę raidinę skaitmeninę eilutę?

Ieškojau paprasto „Java“ algoritmo pseudo-atsitiktinės raidės ir skaitmeninės eilutės generavimui. Mano situacijoje jis bus naudojamas kaip unikali sesija / raktų identifikatorius, kuris „gali būti“ unikalus 500K+ kartos metu (mano poreikiai tikrai nereikalauja nieko sudėtingesnio).

Idealiu atveju galėčiau nurodyti ilgį, priklausomai nuo mano unikalumo poreikių. Pavyzdžiui, sukurta 12 ilgio eilutė gali atrodyti panašiai: "AEYGF7K0DM1X" .

1555
03 сент. set todd 03 sept. 2008-09-03 05:58 '08 at 5:58 am 2008-09-03 05:58
@ 44 atsakymai
  • 1
  • 2

Algoritmas

Norėdami sukurti atsitiktinę eilutę, sujunkite simbolius, atsitiktinai sudarytus iš galiojančių simbolių rinkinio, kol eilutė pasiekia norimą ilgį.

Įgyvendinimas

Štai keletas gana paprastų ir labai lanksčių kodų atsitiktinių ID generavimui. Perskaitykite informaciją, susijusią su svarbiomis taikomosiomis pastabomis.

 import java.security.SecureRandom; import java.util.Locale; import java.util.Objects; import java.util.Random; public class RandomString {  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]; }  public RandomString(int length, Random random) { this(length, random, alphanum); }  public RandomString(int length) { this(length, new SecureRandom()); }  public RandomString() { this(21); } } 

Naudojimo pavyzdžiai

Sukurti nesaugų generatorių 8 simbolių identifikatoriams:

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

Sukurti saugų generatoriaus sesijos ID:

 RandomString session = new RandomString(); 

Sukurti generatorių su nuskaitymais spausdinimo kodais. Stygos yra ilgesnės už raidines ir skaitmenines eilutes, kad kompensuotų mažiau simbolių:

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

Naudokite kaip sesijos identifikatorius

Nepakanka generuoti sesijos identifikatorių, kurie gali būti unikalūs, arba galite tiesiog naudoti paprastą skaitiklį. Užpuolikai perima sesijas, kai naudojami numatomi identifikatoriai.

Yra įtampa tarp ilgio ir saugos. Trumpesni identifikatoriai yra lengviau atspėti, nes yra mažiau funkcijų. Tačiau ilgesni identifikatoriai sunaudoja daugiau atminties ir pralaidumo. Didelis simbolių rinkinys padeda, bet gali sukelti kodavimo problemas, jei identifikatoriai yra įtraukti į URL arba įvesti rankiniu būdu.

Pagrindinis seansų identifikatorių atsitiktinumo ar entropijos šaltinis turi būti atsitiktinių skaičių generatorius, skirtas kriptografijai. Tačiau šių generatorių inicijavimas kartais gali būti brangus ar lėtas, todėl turėtų būti stengiamasi jas pakartotinai panaudoti, kai įmanoma.

Naudokite kaip objektų identifikatorius

Ne kiekvienai programai reikalingas saugumas. Atsitiktinis priskyrimas gali būti veiksmingas būdas keliems objektams generuoti identifikatorius bendroje erdvėje be jokio koordinavimo ar atskyrimo. Koordinavimas gali būti lėtas, ypač klasterizuotoje ar paskirstytoje aplinkoje, o erdvės atskyrimas sukelia problemų, kai daiktai baigiasi per mažais arba per dideliais ištekliais.

Identifikatoriai, sukurti nesikreipiant į jų nenuspėjamumą, turėtų būti apsaugoti kitais būdais, jei užpuolikas gali juos peržiūrėti ir manipuliuoti, kaip daugelyje žiniatinklio programų. Turėtų būti atskira autorizacijos sistema, kuri apsaugotų objektus, kurių identifikatorius gali būti užpuolikas be prieigos leidimo.

Taip pat turėtumėte pasirūpinti, kad identifikatoriai būtų pakankamai ilgai, kad susidūrimai būtų mažai tikėtini, atsižvelgiant į numatomą bendrą identifikatorių skaičių. Tai vadinama „gimtadienio paradoksu“. Susidūrimo tikimybė, p, yra maždaug lygi n 2 / (2q x ), kur n yra faktiškai generuojamų identifikatorių skaičius, q yra skirtingų simbolių skaičius abėcėlėje, o x - identifikatorių ilgis. Tai turėtų būti labai mažas skaičius, pavyzdžiui, 2-50 ar mažiau.

Išsiaiškinus tai rodo, kad 500 k 15 simbolių identifikatorių susidūrimo tikimybė yra apie 2–52, o tai tikriausiai yra mažesnė tikimybė nei nenustatytų kosminių spindulių klaidų ir pan.

Palyginimas su UUID

Pagal jų specifikaciją UUID nėra numatomi ir jie neturėtų būti naudojami kaip seanso identifikatoriai.

UUID standartiniame formate užima daug vietos: 36 simboliai tik 122 bitų entropijos. (Ne visi „atsitiktinio“ UUID bitai yra atsitiktinai parinkti.) Atsitiktinai pasirinkta raidinė ir skaitmeninė eilutė pateikia daugiau entropijos tik į 21 simbolį.

UUID nėra lankstūs; jie turi standartizuotą struktūrą ir vietą. Tai yra jų pagrindinis privalumas ir pagrindinis jų trūkumas. Bendradarbiaudami su išorės šalimi, UUID siūloma standartizacija gali būti naudinga. Grynai vidaus naudojimui jie gali būti neveiksmingi.

1456 m
03 сент. atsakymas pateikiamas erickson 03 Sep. 2008-09-03 07:04 '08 at 7:04 2008-09-03 07:04

„Java“ suteikia galimybę tai padaryti tiesiogiai. Jei nenorite brūkšnelių, juos lengva pjauti. Tiesiog naudokite 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; } } 
border=0

Išvada:

 uuid = 2d7428a6-b58c-4008-8575-f05549f16316 
769
03 сент. Atsakymą pateikė Steve McLeod 03 Sep. 2008-09-03 17:18 '08, 17:18, 2008-09-03 17:18
 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(); } 
500
01 окт. atsakymas pateikiamas maks. 01 okt. 2008-10-01 14:36 '08 ne 14:36 2008-10-01 14:36

Jei džiaugiatės, kad naudojate „Apache“ klases, galite naudoti org.apache.commons.text.RandomStringGenerator (commons-text).

Pavyzdys:

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

Kadangi commons->RandomStringUtils pasenęs.

467
04 сент. atsakymas pateikiamas cmsherratt 04 sep . 2008-09-04 14:14 '08, 14:14 val. 2008-09-04 14:14

Vienoje eilutėje:

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

http://mynotes.wordpress.com/2009/07/23/java-generating-random-string/

99
17 сент. atsakymas pateikiamas anonimiškai . 2009-09-17 18:22 '09 at 18:22 PM 2009-09-17 18:22

Šiam tikslui galite naudoti „Apache“ biblioteką: „ RandomStringUtils“

 RandomStringUtils.randomAlphanumeric(20).toUpperCase(); 
95
20 июля '12 в 13:23 2012-07-20 13:23 atsakymą pateikė manish_s, liepos 20 d., 12 val., 13:23 val. 2012-07-20 13:23

Tai galima lengvai pasiekti be jokių išorinių bibliotekų.

1. Kriptografinė pseudo-atsitiktinių duomenų generacija

Pirmiausia reikia kriptografinio PRNG. „Java“ yra „ SecureRandom , kuriam paprastai naudojamas geriausias entropijos šaltinis (pvz., /dev/random ). Sužinokite daugiau čia.

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

Pastaba SecureRandom yra lėčiausias, bet saugiausias būdas sukurti atsitiktinius baitus „Java“. Tačiau aš rekomenduoju NE apsvarstyti našumą čia, nes ji paprastai neturi jokios įtakos jūsų paraiškai, nebent jums reikia generuoti milijonus žetonų per sekundę.

2. Reikalingų vertybių reikalinga erdvė

Tada turite nuspręsti, kaip unikalus turėtų būti jūsų raktas. Vienintelė priežastis apsvarstyti entropiją yra įsitikinti, kad sistema gali atlaikyti atakas, naudojant brutalią jėgą: galimų verčių erdvė turi būti tokia didelė, kad bet kuris puolėjas gali išbandyti tik nedidelę vertybių dalį absurdišku laiku 1 . Unikalūs identifikatoriai, pvz., Atsitiktinis UUID turi 122 bitų entropiją (ty 2 ^ 122 = 5.3x10 ^ 36) - susidūrimo tikimybė yra „* (...), nes dubliavimo tikimybė yra viena per milijardą, 103 trilijonai UUID 4 versija turi būti sukurta 2 ". Mes pasirinksime 128 bitus, nes ji tiksliai atitinka 16 baitų ir yra pakankamai pakankama, kad ji būtų unikali daugiausia kiekvienam, bet labiausiai ekstremaliam naudojimui, ir jums nereikia galvoti apie dublikatus. Čia yra paprastas entropijos palyginimo lentelė, įskaitant paprastą gimtadienio problemos analizę.

2019

28 мая '17 в 15:06 2017-05-28 15:06 Patrickf atsakymas, pateiktas gegužės 28 d., 17 d. 15:06

naudojant „ Dollar“ turėtų būti paprasta:

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

Tai daroma:

 DKL1SBH9UJWC JH7P0IT21EA5 5DTI72EO6SFU HQUMJTEBNF7Y 1HCR6SKYWGT7 
41
01 февр. atsakymas pateikiamas dfa 01 vasario mėn. 2010-02-01 20:12 '10, 20:12, 2010-02-01 20:12

Keista, kad čia niekas nepasiūlė, bet:

 import java.util.UUID UUID.randomUUID().toString(); 

Lengva

To privalumas yra tas, kad UUID yra geras ir ilgas ir beveik neįmanoma susidurti.

Vikipedija turi gerą paaiškinimą:

„... tik po to, kai per artimiausius 100 metų generuos 1 milijardą UUID kas antrą kartą, tik vienos dublikato sukūrimo tikimybė bus apie 50%.

http://en.wikipedia.org/wiki/Universally_unique_identifier#Random_UUID_probability_of_duplicates

Pirmieji 4 bitai yra versijos tipas ir 2 variantui, todėl jūs gaunate 122 bitų atsitiktinių verčių. Todėl, jei norite, galite pabaigoje sutrumpinti UUID dydį. Tai nerekomenduojama, bet jūs vis dar turite daug atsitiktinumo, pakanka 500k įrašams.

31
25 окт. Michael Allen atsakymas, pateiktas spalio 25 d 2012-10-25 18:45 '12, 18:45, 2012-10-25 18:45

Čia yra Java:

 import static java.> 

Čia pateikiamas pavyzdys:

 scala> RandomAlphaNum.gen(42) res3: java.> 
30
03 сент. Atsakymą pateikė Apocalisp 03 Sep. 2008-09-03 07:37 '08 at 7:37 AM 2008-09-03 07:37

Trumpas ir paprastas sprendimas, tačiau naudojamas tik mažosios raidės ir skaičiai:

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

Dydis yra nuo 12 skaitmenų iki 36 ir negali būti toliau tobulinamas. Žinoma, galite pridėti keletą atvejų.

25
17 апр. atsakymas suteiktas vartotojui nežinomas 17 Bal 2012-04-17 13:08 '12, 13:08 2012-04-17 13:08

Alternatyva „Java 8“ yra:

 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(); } 
13
25 нояб. Atsakymą pateikė Howard Lovatt lapkričio 25 d 2014-11-25 10:23 '14, 10:23 AM 2014-11-25 10:23
 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; } 
10
09 окт. atsakymas pateikiamas rina 09 okt. 2012-10-09 07:40 '12 at 7:40 2012-10-09 07:40
 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 = "!@#$%^ 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); } } 

Taigi, ką tai reiškia, tiesiog pridėkite slaptažodį prie eilutės ir ... taip, patikrinkite jį gerai ... labai paprasta. Aš jį parašiau

9
16 апр. atsakymas pateikiamas cmpbah balandžio 16 d 2012-04-16 18:48 '12 at 18:48 PM 2012-04-16 18:48

Naudojant UUID nėra saugus, nes UUID dalys nėra visiškai atsitiktinės. @Erickson procedūra yra labai tvarkinga, bet nesukuria tos pačios ilgio eilutės. Turėtų pakakti šio fragmento:

  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, random) .toString(32)).replace('\u0020', '0'); } } 

Kodėl verta rinktis length*5 . Tarkime, mes prisiimame paprastą 1 atsitiktinės eilutės, taigi, vieno atsitiktinio pobūdžio, atvejį. Norėdami gauti atsitiktinį simbolį, kuriame yra visi skaitmenys 0-9 ir simboliai az, mums reikia atsitiktinio skaičiaus nuo 0 iki 35, kad gautumėte vieną iš kiekvieno simbolio. BigInteger pateikia konstruktorių, skirtą atsitiktiniam skaičiui, tolygiai paskirstytam intervale nuo 0 to (2^numBits - 1) . Deja, 35 nėra skaičius, kurį galima gauti 2 ^ numBits - 1. Taigi, mes turime dvi parinktis: arba eikite su 2^5-1=31 , arba 2^6-1=63 . Jei pasirinkome 2^6 , mes gausime daug „ekstra“ / „ilgesnių“ numerių. Todėl 2^5 yra geriausias variantas, net jei prarandame 4 simbolius (wz). Norėdami sukurti tam tikro ilgio eilutę, mes galime tiesiog naudoti skaičių 2^(length*numBits)-1 . Paskutinė problema, jei reikalinga tam tikro ilgio eilutė, atsitiktinė, gali generuoti nedidelį skaičių, todėl ilgis nėra patenkintas, todėl privalome nustatyti reikiamą ilgį, todėl nuliai.

9
04 июля '15 в 1:07 2015-07-04 01:07 Atsakymą pateikė Kristianas Kraljicas liepos 4 d. 15 d. 1:07 2015-07-04 01:07

Radau šį sprendimą, kuris generuoja atsitiktinę šešioliktainę koduotą eilutę. Pateiktas vieneto testas, atrodo, palaiko mano pagrindinio naudojimo atvejį. Nors tai yra šiek tiek sudėtingesnis nei kiti atsakymai.

  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;  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); } } } 
7
03 сент. Atsakymas duotas Todd 03 Sep. 2008-09-03 17:22 '08 at 17:22 pm 2008-09-03 17:22
 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
19 окт. atsakymas duotas Jameskittu 19 okt. 2011-10-19 07:36 '11 at 7:36 2011-10-19 07:36
 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); } } } 
6
30 июня '11 в 8:34 2011-06-30 08:34 atsakymą pateikė „ Suganya “ birželio 30 d. 11 val. 8:34 2011-06-30 08:34
  • Pakeiskite eilutės simbolius, kad jie atitiktų jūsų poreikius.

  • Styga nekeičiama. Čia StringBuilder.append efektyvesnis už styginių susiejimą.


 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(); } 
6
06 февр. atsakymas duotas deepakmodak 06 Feb. 2014-02-06 16:15 '14 at 16:15 2014-02-06 16:15

Paminėjote „paprastą“, bet tik tuo atveju, jei kas nors ieško kažko, kas atitinka griežtesnius saugumo reikalavimus, galite žiūrėti „ jpwgen“ . jpwgen yra modeliuotas po „ pwgen “ „Unix“ ir yra labai pritaikomas.

5
10 сент. Atsakymas pateikiamas michaelok 10 rugsėjis 2011-09-10 00:23 '11 prie 0:23 2011-09-10 00:23

Nesvarbu, koks nors iš šių atsakymų dėl „paprasto“ sprendimo: S

Aš norėčiau pasirinkti paprastą;), grynas java, vienas įdėklas (entropija grindžiama atsitiktine eilutės ilgiu ir tam tikru simbolių rinkiniu):

 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"));//charachterSet can basically be anything } }