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.util.Random;
020
021/**
022 * <p>Operations for random {@code String}s.</p>
023 * <p>Currently <em>private high surrogate</em> characters are ignored.
024 * These are Unicode characters that fall between the values 56192 (db80)
025 * and 56319 (dbff) as we don't know how to handle them.
026 * High and low surrogates are correctly dealt with - that is if a
027 * high surrogate is randomly chosen, 55296 (d800) to 56191 (db7f)
028 * then it is followed by a low surrogate. If a low surrogate is chosen,
029 * 56320 (dc00) to 57343 (dfff) then it is placed after a randomly
030 * chosen high surrogate.</p>
031 * <p>RandomStringUtils is intended for simple use cases. For more advanced
032 * use cases consider using commons-text
033 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/RandomStringGenerator.html">
034 * RandomStringGenerator</a> instead.</p>
035 *
036 * <p>Caveat: Instances of {@link Random}, upon which the implementation of this
037 * class relies, are not cryptographically secure.</p>
038 *
039 * <p>Please note that the Apache Commons project provides a component
040 * dedicated to pseudo-random number generation, namely
041 * <a href="https://commons.apache.org/rng">Commons RNG</a>, that may be
042 * a better choice for applications with more stringent requirements
043 * (performance and/or correctness).</p>
044 *
045 * <p>#ThreadSafe#</p>
046 * @since 1.0
047 */
048public class RandomStringUtils {
049
050    /**
051     * <p>Random object used by random method. This has to be not local
052     * to the random method so as to not return the same value in the
053     * same millisecond.</p>
054     */
055    private static final Random RANDOM = new Random();
056
057    /**
058     * <p>{@code RandomStringUtils} instances should NOT be constructed in
059     * standard programming. Instead, the class should be used as
060     * {@code RandomStringUtils.random(5);}.</p>
061     *
062     * <p>This constructor is public to permit tools that require a JavaBean instance
063     * to operate.</p>
064     */
065    public RandomStringUtils() {
066      super();
067    }
068
069    // Random
070    //-----------------------------------------------------------------------
071    /**
072     * <p>Creates a random string whose length is the number of characters
073     * specified.</p>
074     *
075     * <p>Characters will be chosen from the set of all characters.</p>
076     *
077     * @param count  the length of random string to create
078     * @return the random string
079     */
080    public static String random(final int count) {
081        return random(count, false, false);
082    }
083
084    /**
085     * <p>Creates a random string whose length is the number of characters
086     * specified.</p>
087     *
088     * <p>Characters will be chosen from the set of characters whose
089     * ASCII value is between {@code 32} and {@code 126} (inclusive).</p>
090     *
091     * @param count  the length of random string to create
092     * @return the random string
093     */
094    public static String randomAscii(final int count) {
095        return random(count, 32, 127, false, false);
096    }
097
098    /**
099     * <p>Creates a random string whose length is between the inclusive minimum and
100     * the exclusive maximum.</p>
101     *
102     * <p>Characters will be chosen from the set of characters whose
103     * ASCII value is between {@code 32} and {@code 126} (inclusive).</p>
104     *
105     * @param minLengthInclusive the inclusive minimum length of the string to generate
106     * @param maxLengthExclusive the exclusive maximum length of the string to generate
107     * @return the random string
108     * @since 3.5
109     */
110    public static String randomAscii(final int minLengthInclusive, final int maxLengthExclusive) {
111        return randomAscii(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive));
112    }
113
114    /**
115     * <p>Creates a random string whose length is the number of characters
116     * specified.</p>
117     *
118     * <p>Characters will be chosen from the set of Latin alphabetic
119     * characters (a-z, A-Z).</p>
120     *
121     * @param count  the length of random string to create
122     * @return the random string
123     */
124    public static String randomAlphabetic(final int count) {
125        return random(count, true, false);
126    }
127
128    /**
129     * <p>Creates a random string whose length is between the inclusive minimum and
130     * the exclusive maximum.</p>
131     *
132     * <p>Characters will be chosen from the set of Latin alphabetic characters (a-z, A-Z).</p>
133     *
134     * @param minLengthInclusive the inclusive minimum length of the string to generate
135     * @param maxLengthExclusive the exclusive maximum length of the string to generate
136     * @return the random string
137     * @since 3.5
138     */
139    public static String randomAlphabetic(final int minLengthInclusive, final int maxLengthExclusive) {
140        return randomAlphabetic(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive));
141    }
142
143    /**
144     * <p>Creates a random string whose length is the number of characters
145     * specified.</p>
146     *
147     * <p>Characters will be chosen from the set of Latin alphabetic
148     * characters (a-z, A-Z) and the digits 0-9.</p>
149     *
150     * @param count  the length of random string to create
151     * @return the random string
152     */
153    public static String randomAlphanumeric(final int count) {
154        return random(count, true, true);
155    }
156
157    /**
158     * <p>Creates a random string whose length is between the inclusive minimum and
159     * the exclusive maximum.</p>
160     *
161     * <p>Characters will be chosen from the set of Latin alphabetic
162     * characters (a-z, A-Z) and the digits 0-9.</p>
163     *
164     * @param minLengthInclusive the inclusive minimum length of the string to generate
165     * @param maxLengthExclusive the exclusive maximum length of the string to generate
166     * @return the random string
167     * @since 3.5
168     */
169    public static String randomAlphanumeric(final int minLengthInclusive, final int maxLengthExclusive) {
170        return randomAlphanumeric(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive));
171    }
172
173    /**
174     * <p>Creates a random string whose length is the number of characters specified.</p>
175     *
176     * <p>Characters will be chosen from the set of characters which match the POSIX [:graph:]
177     * regular expression character class. This class contains all visible ASCII characters
178     * (i.e. anything except spaces and control characters).</p>
179     *
180     * @param count  the length of random string to create
181     * @return the random string
182     * @since 3.5
183     */
184    public static String randomGraph(final int count) {
185        return random(count, 33, 126, false, false);
186    }
187
188    /**
189     * <p>Creates a random string whose length is between the inclusive minimum and
190     * the exclusive maximum.</p>
191     *
192     * <p>Characters will be chosen from the set of \p{Graph} characters.</p>
193     *
194     * @param minLengthInclusive the inclusive minimum length of the string to generate
195     * @param maxLengthExclusive the exclusive maximum length of the string to generate
196     * @return the random string
197     * @since 3.5
198     */
199    public static String randomGraph(final int minLengthInclusive, final int maxLengthExclusive) {
200        return randomGraph(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive));
201    }
202
203    /**
204     * <p>Creates a random string whose length is the number of characters
205     * specified.</p>
206     *
207     * <p>Characters will be chosen from the set of numeric
208     * characters.</p>
209     *
210     * @param count  the length of random string to create
211     * @return the random string
212     */
213    public static String randomNumeric(final int count) {
214        return random(count, false, true);
215    }
216
217    /**
218     * <p>Creates a random string whose length is between the inclusive minimum and
219     * the exclusive maximum.</p>
220     *
221     * <p>Characters will be chosen from the set of \p{Digit} characters.</p>
222     *
223     * @param minLengthInclusive the inclusive minimum length of the string to generate
224     * @param maxLengthExclusive the exclusive maximum length of the string to generate
225     * @return the random string
226     * @since 3.5
227     */
228    public static String randomNumeric(final int minLengthInclusive, final int maxLengthExclusive) {
229        return randomNumeric(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive));
230    }
231
232    /**
233     * <p>Creates a random string whose length is the number of characters specified.</p>
234     *
235     * <p>Characters will be chosen from the set of characters which match the POSIX [:print:]
236     * regular expression character class. This class includes all visible ASCII characters and spaces
237     * (i.e. anything except control characters).</p>
238     *
239     * @param count  the length of random string to create
240     * @return the random string
241     * @since 3.5
242     */
243    public static String randomPrint(final int count) {
244        return random(count, 32, 126, false, false);
245    }
246
247    /**
248     * <p>Creates a random string whose length is between the inclusive minimum and
249     * the exclusive maximum.</p>
250     *
251     * <p>Characters will be chosen from the set of \p{Print} characters.</p>
252     *
253     * @param minLengthInclusive the inclusive minimum length of the string to generate
254     * @param maxLengthExclusive the exclusive maximum length of the string to generate
255     * @return the random string
256     * @since 3.5
257     */
258    public static String randomPrint(final int minLengthInclusive, final int maxLengthExclusive) {
259        return randomPrint(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive));
260    }
261
262    /**
263     * <p>Creates a random string whose length is the number of characters
264     * specified.</p>
265     *
266     * <p>Characters will be chosen from the set of alpha-numeric
267     * characters as indicated by the arguments.</p>
268     *
269     * @param count  the length of random string to create
270     * @param letters  if {@code true}, generated string may include
271     *  alphabetic characters
272     * @param numbers  if {@code true}, generated string may include
273     *  numeric characters
274     * @return the random string
275     */
276    public static String random(final int count, final boolean letters, final boolean numbers) {
277        return random(count, 0, 0, letters, numbers);
278    }
279
280    /**
281     * <p>Creates a random string whose length is the number of characters
282     * specified.</p>
283     *
284     * <p>Characters will be chosen from the set of alpha-numeric
285     * characters as indicated by the arguments.</p>
286     *
287     * @param count  the length of random string to create
288     * @param start  the position in set of chars to start at
289     * @param end  the position in set of chars to end before
290     * @param letters  if {@code true}, generated string may include
291     *  alphabetic characters
292     * @param numbers  if {@code true}, generated string may include
293     *  numeric characters
294     * @return the random string
295     */
296    public static String random(final int count, final int start, final int end, final boolean letters, final boolean numbers) {
297        return random(count, start, end, letters, numbers, null, RANDOM);
298    }
299
300    /**
301     * <p>Creates a random string based on a variety of options, using
302     * default source of randomness.</p>
303     *
304     * <p>This method has exactly the same semantics as
305     * {@link #random(int,int,int,boolean,boolean,char[],Random)}, but
306     * instead of using an externally supplied source of randomness, it uses
307     * the internal static {@link Random} instance.</p>
308     *
309     * @param count  the length of random string to create
310     * @param start  the position in set of chars to start at
311     * @param end  the position in set of chars to end before
312     * @param letters  only allow letters?
313     * @param numbers  only allow numbers?
314     * @param chars  the set of chars to choose randoms from.
315     *  If {@code null}, then it will use the set of all chars.
316     * @return the random string
317     * @throws ArrayIndexOutOfBoundsException if there are not
318     *  {@code (end - start) + 1} characters in the set array.
319     */
320    public static String random(final int count, final int start, final int end, final boolean letters, final boolean numbers, final char... chars) {
321        return random(count, start, end, letters, numbers, chars, RANDOM);
322    }
323
324    /**
325     * <p>Creates a random string based on a variety of options, using
326     * supplied source of randomness.</p>
327     *
328     * <p>If start and end are both {@code 0}, start and end are set
329     * to {@code ' '} and {@code 'z'}, the ASCII printable
330     * characters, will be used, unless letters and numbers are both
331     * {@code false}, in which case, start and end are set to
332     * {@code 0} and {@link Character#MAX_CODE_POINT}.
333     *
334     * <p>If set is not {@code null}, characters between start and
335     * end are chosen.</p>
336     *
337     * <p>This method accepts a user-supplied {@link Random}
338     * instance to use as a source of randomness. By seeding a single
339     * {@link Random} instance with a fixed seed and using it for each call,
340     * the same random sequence of strings can be generated repeatedly
341     * and predictably.</p>
342     *
343     * @param count  the length of random string to create
344     * @param start  the position in set of chars to start at (inclusive)
345     * @param end  the position in set of chars to end before (exclusive)
346     * @param letters  only allow letters?
347     * @param numbers  only allow numbers?
348     * @param chars  the set of chars to choose randoms from, must not be empty.
349     *  If {@code null}, then it will use the set of all chars.
350     * @param random  a source of randomness.
351     * @return the random string
352     * @throws ArrayIndexOutOfBoundsException if there are not
353     *  {@code (end - start) + 1} characters in the set array.
354     * @throws IllegalArgumentException if {@code count} &lt; 0 or the provided chars array is empty.
355     * @since 2.0
356     */
357    public static String random(int count, int start, int end, final boolean letters, final boolean numbers,
358                                final char[] chars, final Random random) {
359        if (count == 0) {
360            return StringUtils.EMPTY;
361        } else if (count < 0) {
362            throw new IllegalArgumentException("Requested random string length " + count + " is less than 0.");
363        }
364        if (chars != null && chars.length == 0) {
365            throw new IllegalArgumentException("The chars array must not be empty");
366        }
367
368        if (start == 0 && end == 0) {
369            if (chars != null) {
370                end = chars.length;
371            } else {
372                if (!letters && !numbers) {
373                    end = Character.MAX_CODE_POINT;
374                } else {
375                    end = 'z' + 1;
376                    start = ' ';
377                }
378            }
379        } else {
380            if (end <= start) {
381                throw new IllegalArgumentException("Parameter end (" + end + ") must be greater than start (" + start + ")");
382            }
383        }
384
385        final int zero_digit_ascii = 48;
386        final int first_letter_ascii = 65;
387
388        if (chars == null && (numbers && end <= zero_digit_ascii
389                || letters && end <= first_letter_ascii)) {
390            throw new IllegalArgumentException("Parameter end (" + end + ") must be greater then (" + zero_digit_ascii + ") for generating digits " +
391                    "or greater then (" + first_letter_ascii + ") for generating letters.");
392        }
393
394        final StringBuilder builder = new StringBuilder(count);
395        final int gap = end - start;
396
397        while (count-- != 0) {
398            int codePoint;
399            if (chars == null) {
400                codePoint = random.nextInt(gap) + start;
401
402                switch (Character.getType(codePoint)) {
403                case Character.UNASSIGNED:
404                case Character.PRIVATE_USE:
405                case Character.SURROGATE:
406                    count++;
407                    continue;
408                }
409
410            } else {
411                codePoint = chars[random.nextInt(gap) + start];
412            }
413
414            final int numberOfChars = Character.charCount(codePoint);
415            if (count == 0 && numberOfChars > 1) {
416                count++;
417                continue;
418            }
419
420            if (letters && Character.isLetter(codePoint)
421                    || numbers && Character.isDigit(codePoint)
422                    || !letters && !numbers) {
423                builder.appendCodePoint(codePoint);
424
425                if (numberOfChars == 2) {
426                    count--;
427                }
428
429            } else {
430                count++;
431            }
432        }
433        return builder.toString();
434    }
435
436
437    /**
438     * <p>Creates a random string whose length is the number of characters
439     * specified.</p>
440     *
441     * <p>Characters will be chosen from the set of characters
442     * specified by the string, must not be empty.
443     * If null, the set of all characters is used.</p>
444     *
445     * @param count  the length of random string to create
446     * @param chars  the String containing the set of characters to use,
447     *  may be null, but must not be empty
448     * @return the random string
449     * @throws IllegalArgumentException if {@code count} &lt; 0 or the string is empty.
450     */
451    public static String random(final int count, final String chars) {
452        if (chars == null) {
453            return random(count, 0, 0, false, false, null, RANDOM);
454        }
455        return random(count, chars.toCharArray());
456    }
457
458    /**
459     * <p>Creates a random string whose length is the number of characters
460     * specified.</p>
461     *
462     * <p>Characters will be chosen from the set of characters specified.</p>
463     *
464     * @param count  the length of random string to create
465     * @param chars  the character array containing the set of characters to use,
466     *  may be null
467     * @return the random string
468     * @throws IllegalArgumentException if {@code count} &lt; 0.
469     */
470    public static String random(final int count, final char... chars) {
471        if (chars == null) {
472            return random(count, 0, 0, false, false, null, RANDOM);
473        }
474        return random(count, 0, chars.length, false, false, chars, RANDOM);
475    }
476
477}