001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.lang3; 018 019import java.security.NoSuchAlgorithmException; 020import java.security.SecureRandom; 021import java.util.Random; 022import java.util.concurrent.ThreadLocalRandom; 023 024import org.apache.commons.lang3.exception.UncheckedException; 025 026/** 027 * Generates random {@link String}s. 028 * <p> 029 * Starting in version 3.15.0, this classes uses {@link SecureRandom#getInstanceStrong()}. 030 * </p> 031 * <p> 032 * Before version 3.15.0, this classes used {@link ThreadLocalRandom#current()}, which was NOT cryptographically secure. 033 * </p> 034 * <p> 035 * RandomStringUtils is intended for simple use cases. For more advanced use cases consider using Apache Commons Text's 036 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/RandomStringGenerator.html"> RandomStringGenerator</a> 037 * instead. 038 * </p> 039 * <p> 040 * The Apache Commons project provides <a href="https://commons.apache.org/proper/commons-rng/">Commons RNG</a> dedicated to pseudo-random number generation, 041 * that may be a better choice for applications with more stringent requirements (performance and/or correctness). 042 * </p> 043 * <p> 044 * Note that <em>private high surrogate</em> characters are ignored. These are Unicode characters that fall between the values 56192 (db80) and 56319 (dbff) as 045 * we don't know how to handle them. High and low surrogates are correctly dealt with - that is if a high surrogate is randomly chosen, 55296 (d800) to 56191 046 * (db7f) then it is followed by a low surrogate. If a low surrogate is chosen, 56320 (dc00) to 57343 (dfff) then it is placed after a randomly chosen high 047 * surrogate. 048 * </p> 049 * <p> 050 * #ThreadSafe# 051 * </p> 052 * 053 * @since 1.0 054 */ 055public class RandomStringUtils { 056 057 private static final ThreadLocal<SecureRandom> RANDOM = ThreadLocal.withInitial(() -> { 058 try { 059 return SecureRandom.getInstanceStrong(); 060 } catch (NoSuchAlgorithmException e) { 061 throw new UncheckedException(e); 062 } 063 }); 064 065 static SecureRandom random() { 066 return RANDOM.get(); 067 } 068 069 private static final char[] ALPHANUMERICAL_CHARS = { 070 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 071 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 072 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 073 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 074 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 075 }; 076 077 /** 078 * Creates a random string whose length is the number of characters 079 * specified. 080 * 081 * <p>Characters will be chosen from the set of all characters.</p> 082 * 083 * @param count the length of random string to create 084 * @return the random string 085 * @throws IllegalArgumentException if {@code count} < 0. 086 */ 087 public static String random(final int count) { 088 return random(count, false, false); 089 } 090 091 /** 092 * Creates a random string whose length is the number of characters 093 * specified. 094 * 095 * <p>Characters will be chosen from the set of alpha-numeric 096 * characters as indicated by the arguments.</p> 097 * 098 * @param count the length of random string to create 099 * @param letters if {@code true}, generated string may include 100 * alphabetic characters 101 * @param numbers if {@code true}, generated string may include 102 * numeric characters 103 * @return the random string 104 * @throws IllegalArgumentException if {@code count} < 0. 105 */ 106 public static String random(final int count, final boolean letters, final boolean numbers) { 107 return random(count, 0, 0, letters, numbers); 108 } 109 110 /** 111 * Creates a random string whose length is the number of characters 112 * specified. 113 * 114 * <p>Characters will be chosen from the set of characters specified.</p> 115 * 116 * @param count the length of random string to create 117 * @param chars the character array containing the set of characters to use, 118 * may be null 119 * @return the random string 120 * @throws IllegalArgumentException if {@code count} < 0. 121 */ 122 public static String random(final int count, final char... chars) { 123 if (chars == null) { 124 return random(count, 0, 0, false, false, null, random()); 125 } 126 return random(count, 0, chars.length, false, false, chars, random()); 127 } 128 129 /** 130 * Creates a random string whose length is the number of characters 131 * specified. 132 * 133 * <p>Characters will be chosen from the set of alpha-numeric 134 * characters as indicated by the arguments.</p> 135 * 136 * @param count the length of random string to create 137 * @param start the position in set of chars to start at 138 * @param end the position in set of chars to end before 139 * @param letters if {@code true}, generated string may include 140 * alphabetic characters 141 * @param numbers if {@code true}, generated string may include 142 * numeric characters 143 * @return the random string 144 * @throws IllegalArgumentException if {@code count} < 0. 145 */ 146 public static String random(final int count, final int start, final int end, final boolean letters, final boolean numbers) { 147 return random(count, start, end, letters, numbers, null, random()); 148 } 149 150 /** 151 * Creates a random string based on a variety of options, using 152 * default source of randomness. 153 * 154 * <p>This method has exactly the same semantics as 155 * {@link #random(int,int,int,boolean,boolean,char[],Random)}, but 156 * instead of using an externally supplied source of randomness, it uses 157 * the internal static {@link Random} instance.</p> 158 * 159 * @param count the length of random string to create 160 * @param start the position in set of chars to start at 161 * @param end the position in set of chars to end before 162 * @param letters if {@code true}, generated string may include 163 * alphabetic characters 164 * @param numbers if {@code true}, generated string may include 165 * numeric characters 166 * @param chars the set of chars to choose randoms from. 167 * If {@code null}, then it will use the set of all chars. 168 * @return the random string 169 * @throws ArrayIndexOutOfBoundsException if there are not 170 * {@code (end - start) + 1} characters in the set array. 171 * @throws IllegalArgumentException if {@code count} < 0. 172 */ 173 public static String random(final int count, final int start, final int end, final boolean letters, final boolean numbers, final char... chars) { 174 return random(count, start, end, letters, numbers, chars, random()); 175 } 176 177 /** 178 * Creates a random string based on a variety of options, using 179 * supplied source of randomness. 180 * 181 * <p>If start and end are both {@code 0}, start and end are set 182 * to {@code ' '} and {@code 'z'}, the ASCII printable 183 * characters, will be used, unless letters and numbers are both 184 * {@code false}, in which case, start and end are set to 185 * {@code 0} and {@link Character#MAX_CODE_POINT}. 186 * 187 * <p>If set is not {@code null}, characters between start and 188 * end are chosen.</p> 189 * 190 * <p>This method accepts a user-supplied {@link Random} 191 * instance to use as a source of randomness. By seeding a single 192 * {@link Random} instance with a fixed seed and using it for each call, 193 * the same random sequence of strings can be generated repeatedly 194 * and predictably.</p> 195 * 196 * @param count the length of random string to create 197 * @param start the position in set of chars to start at (inclusive) 198 * @param end the position in set of chars to end before (exclusive) 199 * @param letters if {@code true}, generated string may include 200 * alphabetic characters 201 * @param numbers if {@code true}, generated string may include 202 * numeric characters 203 * @param chars the set of chars to choose randoms from, must not be empty. 204 * If {@code null}, then it will use the set of all chars. 205 * @param random a source of randomness. 206 * @return the random string 207 * @throws ArrayIndexOutOfBoundsException if there are not 208 * {@code (end - start) + 1} characters in the set array. 209 * @throws IllegalArgumentException if {@code count} < 0 or the provided chars array is empty. 210 * @since 2.0 211 */ 212 public static String random(int count, int start, int end, final boolean letters, final boolean numbers, 213 final char[] chars, final Random random) { 214 if (count == 0) { 215 return StringUtils.EMPTY; 216 } 217 if (count < 0) { 218 throw new IllegalArgumentException("Requested random string length " + count + " is less than 0."); 219 } 220 if (chars != null && chars.length == 0) { 221 throw new IllegalArgumentException("The chars array must not be empty"); 222 } 223 224 if (start == 0 && end == 0) { 225 if (chars != null) { 226 end = chars.length; 227 } else if (!letters && !numbers) { 228 end = Character.MAX_CODE_POINT; 229 } else { 230 end = 'z' + 1; 231 start = ' '; 232 } 233 } else if (end <= start) { 234 throw new IllegalArgumentException("Parameter end (" + end + ") must be greater than start (" + start + ")"); 235 } 236 237 if (end > Character.MAX_CODE_POINT) { 238 // Technically, it should be `Character.MAX_CODE_POINT+1` as `end` is excluded 239 // But the character `Character.MAX_CODE_POINT` is private use, so it would anyway be excluded 240 end = Character.MAX_CODE_POINT; 241 } 242 243 // Optimize generation of full alphanumerical characters 244 // Normally, we would need to pick a 7-bit integer, since gap = 'z' - '0' + 1 = 75 > 64 245 // In turn, this would make us reject the sampling with probability 1 - 62 / 2^7 > 1 / 2 246 // Instead we can pick directly from the right set of 62 characters, which requires 247 // picking a 6-bit integer and only rejecting with probability 2 / 64 = 1 / 32 248 if (chars == null && letters && numbers && start <= '0' && end >= 'z' + 1) { 249 return random(count, 0, 0, false, false, ALPHANUMERICAL_CHARS, random); 250 } 251 252 // Optimize start and end when filtering by letters and/or numbers: 253 // The range provided may be too large since we filter anyway afterward. 254 // Note the use of Math.min/max (as opposed to setting start to '0' for example), 255 // since it is possible the range start/end excludes some of the letters/numbers, 256 // e.g., it is possible that start already is '1' when numbers = true, and start 257 // needs to stay equal to '1' in that case. 258 if (chars == null) { 259 if (letters && numbers) { 260 start = Math.max('0', start); 261 end = Math.min('z' + 1, end); 262 } else if (numbers) { 263 // just numbers, no letters 264 start = Math.max('0', start); 265 end = Math.min('9' + 1, end); 266 } else if (letters) { 267 // just letters, no numbers 268 start = Math.max('A', start); 269 end = Math.min('z' + 1, end); 270 } 271 } 272 273 final int zeroDigitAscii = 48; 274 final int firstLetterAscii = 65; 275 276 if (chars == null && (numbers && end <= zeroDigitAscii 277 || letters && end <= firstLetterAscii)) { 278 throw new IllegalArgumentException("Parameter end (" + end + ") must be greater then (" + zeroDigitAscii + ") for generating digits " + 279 "or greater then (" + firstLetterAscii + ") for generating letters."); 280 } 281 282 final StringBuilder builder = new StringBuilder(count); 283 final int gap = end - start; 284 final int gapBits = Integer.SIZE - Integer.numberOfLeadingZeros(gap); 285 // The size of the cache we use is an heuristic: 286 // about twice the number of bytes required if no rejection 287 // Ideally the cache size depends on multiple factor, including the cost of generating x bytes 288 // of randomness as well as the probability of rejection. It is however not easy to know 289 // those values programmatically for the general case. 290 final CachedRandomBits arb = new CachedRandomBits((count * gapBits + 3) / 5 + 10, random); 291 292 while (count-- != 0) { 293 // Generate a random value between start (included) and end (excluded) 294 final int randomValue = arb.nextBits(gapBits) + start; 295 // Rejection sampling if value too large 296 if (randomValue >= end) { 297 count++; 298 continue; 299 } 300 301 final int codePoint; 302 if (chars == null) { 303 codePoint = randomValue; 304 305 switch (Character.getType(codePoint)) { 306 case Character.UNASSIGNED: 307 case Character.PRIVATE_USE: 308 case Character.SURROGATE: 309 count++; 310 continue; 311 } 312 313 } else { 314 codePoint = chars[randomValue]; 315 } 316 317 final int numberOfChars = Character.charCount(codePoint); 318 if (count == 0 && numberOfChars > 1) { 319 count++; 320 continue; 321 } 322 323 if (letters && Character.isLetter(codePoint) 324 || numbers && Character.isDigit(codePoint) 325 || !letters && !numbers) { 326 builder.appendCodePoint(codePoint); 327 328 if (numberOfChars == 2) { 329 count--; 330 } 331 332 } else { 333 count++; 334 } 335 } 336 return builder.toString(); 337 } 338 339 /** 340 * Creates a random string whose length is the number of characters 341 * specified. 342 * 343 * <p>Characters will be chosen from the set of characters 344 * specified by the string, must not be empty. 345 * If null, the set of all characters is used.</p> 346 * 347 * @param count the length of random string to create 348 * @param chars the String containing the set of characters to use, 349 * may be null, but must not be empty 350 * @return the random string 351 * @throws IllegalArgumentException if {@code count} < 0 or the string is empty. 352 */ 353 public static String random(final int count, final String chars) { 354 if (chars == null) { 355 return random(count, 0, 0, false, false, null, random()); 356 } 357 return random(count, chars.toCharArray()); 358 } 359 360 /** 361 * Creates a random string whose length is the number of characters 362 * specified. 363 * 364 * <p>Characters will be chosen from the set of Latin alphabetic 365 * characters (a-z, A-Z).</p> 366 * 367 * @param count the length of random string to create 368 * @return the random string 369 * @throws IllegalArgumentException if {@code count} < 0. 370 */ 371 public static String randomAlphabetic(final int count) { 372 return random(count, true, false); 373 } 374 375 /** 376 * Creates a random string whose length is between the inclusive minimum and 377 * the exclusive maximum. 378 * 379 * <p>Characters will be chosen from the set of Latin alphabetic characters (a-z, A-Z).</p> 380 * 381 * @param minLengthInclusive the inclusive minimum length of the string to generate 382 * @param maxLengthExclusive the exclusive maximum length of the string to generate 383 * @return the random string 384 * @since 3.5 385 */ 386 public static String randomAlphabetic(final int minLengthInclusive, final int maxLengthExclusive) { 387 return randomAlphabetic(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); 388 } 389 390 /** 391 * Creates a random string whose length is the number of characters 392 * specified. 393 * 394 * <p>Characters will be chosen from the set of Latin alphabetic 395 * characters (a-z, A-Z) and the digits 0-9.</p> 396 * 397 * @param count the length of random string to create 398 * @return the random string 399 * @throws IllegalArgumentException if {@code count} < 0. 400 */ 401 public static String randomAlphanumeric(final int count) { 402 return random(count, true, true); 403 } 404 405 /** 406 * Creates a random string whose length is between the inclusive minimum and 407 * the exclusive maximum. 408 * 409 * <p>Characters will be chosen from the set of Latin alphabetic 410 * characters (a-z, A-Z) and the digits 0-9.</p> 411 * 412 * @param minLengthInclusive the inclusive minimum length of the string to generate 413 * @param maxLengthExclusive the exclusive maximum length of the string to generate 414 * @return the random string 415 * @since 3.5 416 */ 417 public static String randomAlphanumeric(final int minLengthInclusive, final int maxLengthExclusive) { 418 return randomAlphanumeric(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); 419 } 420 421 /** 422 * Creates a random string whose length is the number of characters 423 * specified. 424 * 425 * <p>Characters will be chosen from the set of characters whose 426 * ASCII value is between {@code 32} and {@code 126} (inclusive).</p> 427 * 428 * @param count the length of random string to create 429 * @return the random string 430 * @throws IllegalArgumentException if {@code count} < 0. 431 */ 432 public static String randomAscii(final int count) { 433 return random(count, 32, 127, false, false); 434 } 435 436 /** 437 * Creates a random string whose length is between the inclusive minimum and 438 * the exclusive maximum. 439 * 440 * <p>Characters will be chosen from the set of characters whose 441 * ASCII value is between {@code 32} and {@code 126} (inclusive).</p> 442 * 443 * @param minLengthInclusive the inclusive minimum length of the string to generate 444 * @param maxLengthExclusive the exclusive maximum length of the string to generate 445 * @return the random string 446 * @since 3.5 447 */ 448 public static String randomAscii(final int minLengthInclusive, final int maxLengthExclusive) { 449 return randomAscii(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); 450 } 451 452 /** 453 * Creates a random string whose length is the number of characters specified. 454 * 455 * <p>Characters will be chosen from the set of characters which match the POSIX [:graph:] 456 * regular expression character class. This class contains all visible ASCII characters 457 * (i.e. anything except spaces and control characters).</p> 458 * 459 * @param count the length of random string to create 460 * @return the random string 461 * @throws IllegalArgumentException if {@code count} < 0. 462 * @since 3.5 463 */ 464 public static String randomGraph(final int count) { 465 return random(count, 33, 126, false, false); 466 } 467 468 /** 469 * Creates a random string whose length is between the inclusive minimum and 470 * the exclusive maximum. 471 * 472 * <p>Characters will be chosen from the set of \p{Graph} characters.</p> 473 * 474 * @param minLengthInclusive the inclusive minimum length of the string to generate 475 * @param maxLengthExclusive the exclusive maximum length of the string to generate 476 * @return the random string 477 * @since 3.5 478 */ 479 public static String randomGraph(final int minLengthInclusive, final int maxLengthExclusive) { 480 return randomGraph(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); 481 } 482 483 /** 484 * Creates a random string whose length is the number of characters 485 * specified. 486 * 487 * <p>Characters will be chosen from the set of numeric 488 * characters.</p> 489 * 490 * @param count the length of random string to create 491 * @return the random string 492 * @throws IllegalArgumentException if {@code count} < 0. 493 */ 494 public static String randomNumeric(final int count) { 495 return random(count, false, true); 496 } 497 498 /** 499 * Creates a random string whose length is between the inclusive minimum and 500 * the exclusive maximum. 501 * 502 * <p>Characters will be chosen from the set of \p{Digit} characters.</p> 503 * 504 * @param minLengthInclusive the inclusive minimum length of the string to generate 505 * @param maxLengthExclusive the exclusive maximum length of the string to generate 506 * @return the random string 507 * @since 3.5 508 */ 509 public static String randomNumeric(final int minLengthInclusive, final int maxLengthExclusive) { 510 return randomNumeric(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); 511 } 512 513 /** 514 * Creates a random string whose length is the number of characters specified. 515 * 516 * <p>Characters will be chosen from the set of characters which match the POSIX [:print:] 517 * regular expression character class. This class includes all visible ASCII characters and spaces 518 * (i.e. anything except control characters).</p> 519 * 520 * @param count the length of random string to create 521 * @return the random string 522 * @throws IllegalArgumentException if {@code count} < 0. 523 * @since 3.5 524 */ 525 public static String randomPrint(final int count) { 526 return random(count, 32, 126, false, false); 527 } 528 529 /** 530 * Creates a random string whose length is between the inclusive minimum and 531 * the exclusive maximum. 532 * 533 * <p>Characters will be chosen from the set of \p{Print} characters.</p> 534 * 535 * @param minLengthInclusive the inclusive minimum length of the string to generate 536 * @param maxLengthExclusive the exclusive maximum length of the string to generate 537 * @return the random string 538 * @since 3.5 539 */ 540 public static String randomPrint(final int minLengthInclusive, final int maxLengthExclusive) { 541 return randomPrint(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); 542 } 543 544 /** 545 * {@link RandomStringUtils} instances should NOT be constructed in 546 * standard programming. Instead, the class should be used as 547 * {@code RandomStringUtils.random(5);}. 548 * 549 * <p>This constructor is public to permit tools that require a JavaBean instance 550 * to operate.</p> 551 * 552 * @deprecated TODO Make private in 4.0. 553 */ 554 @Deprecated 555 public RandomStringUtils() { 556 // empty 557 } 558 559}