    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     */
    017    package org.apache.commons.lang3;
    018
    019    import java.util.Random;
    020    /**
    021     * <p>Operations for random <code>String</code>s.</p>
    022     * <p>Currently <em>private high surrogate</em> characters are ignored.
    023     * These are unicode characters that fall between the values 56192 (db80)
    024     * and 56319 (dbff) as we don't know how to handle them.
    025     * High and low surrogates are correctly dealt with - that is if a
    026     * high surrogate is randomly chosen, 55296 (d800) to 56191 (db7f)
    027     * then it is followed by a low surrogate. If a low surrogate is chosen,
    028     * 56320 (dc00) to 57343 (dfff) then it is placed after a randomly
    029     * chosen high surrogate. </p>
    030     *
    031     * <p>#ThreadSafe#</p>
    032     * @author Apache Software Foundation
    033     * @author <a href="mailto:steven@caswell.name">Steven Caswell</a>
    034     * @author Gary Gregory
    035     * @author Phil Steitz
    036     * @since 1.0
    037     * @version $Id: RandomStringUtils.java 918868 2010-03-04 06:22:16Z bayard $
    038     */
    039    public class RandomStringUtils {
    040
    041        /**
    042         * <p>Random object used by random method. This has to be not local
    043         * to the random method so as to not return the same value in the
    044         * same millisecond.</p>
    045         */
    046        private static final Random RANDOM = new Random();
    047
    048        /**
    049         * <p><code>RandomStringUtils</code> instances should NOT be constructed in
    050         * standard programming. Instead, the class should be used as
    051         * <code>RandomStringUtils.random(5);</code>.</p>
    052         *
    053         * <p>This constructor is public to permit tools that require a JavaBean instance
    054         * to operate.</p>
    055         */
    056        public RandomStringUtils() {
    057          super();
    058        }
    059
    060        // Random
    061        //-----------------------------------------------------------------------
    062        /**
    063         * <p>Creates a random string whose length is the number of characters
    064         * specified.</p>
    065         *
    066         * <p>Characters will be chosen from the set of all characters.</p>
    067         *
    068         * @param count  the length of random string to create
    069         * @return the random string
    070         */
    071        public static String random(int count) {
    072            return random(count, false, false);
    073        }
    074
    075        /**
    076         * <p>Creates a random string whose length is the number of characters
    077         * specified.</p>
    078         *
    079         * <p>Characters will be chosen from the set of characters whose
    080         * ASCII value is between <code>32</code> and <code>126</code> (inclusive).</p>
    081         *
    082         * @param count  the length of random string to create
    083         * @return the random string
    084         */
    085        public static String randomAscii(int count) {
    086            return random(count, 32, 127, false, false);
    087        }
    088
    089        /**
    090         * <p>Creates a random string whose length is the number of characters
    091         * specified.</p>
    092         *
    093         * <p>Characters will be chosen from the set of alphabetic
    094         * characters.</p>
    095         *
    096         * @param count  the length of random string to create
    097         * @return the random string
    098         */
    099        public static String randomAlphabetic(int count) {
    100            return random(count, true, false);
    101        }
    102
    103        /**
    104         * <p>Creates a random string whose length is the number of characters
    105         * specified.</p>
    106         *
    107         * <p>Characters will be chosen from the set of alpha-numeric
    108         * characters.</p>
    109         *
    110         * @param count  the length of random string to create
    111         * @return the random string
    112         */
    113        public static String randomAlphanumeric(int count) {
    114            return random(count, true, true);
    115        }
    116
    117        /**
    118         * <p>Creates a random string whose length is the number of characters
    119         * specified.</p>
    120         *
    121         * <p>Characters will be chosen from the set of numeric
    122         * characters.</p>
    123         *
    124         * @param count  the length of random string to create
    125         * @return the random string
    126         */
    127        public static String randomNumeric(int count) {
    128            return random(count, false, true);
    129        }
    130
    131        /**
    132         * <p>Creates a random string whose length is the number of characters
    133         * specified.</p>
    134         *
    135         * <p>Characters will be chosen from the set of alpha-numeric
    136         * characters as indicated by the arguments.</p>
    137         *
    138         * @param count  the length of random string to create
    139         * @param letters  if <code>true</code>, generated string will include
    140         *  alphabetic characters
    141         * @param numbers  if <code>true</code>, generated string will include
    142         *  numeric characters
    143         * @return the random string
    144         */
    145        public static String random(int count, boolean letters, boolean numbers) {
    146            return random(count, 0, 0, letters, numbers);
    147        }
    148
    149        /**
    150         * <p>Creates a random string whose length is the number of characters
    151         * specified.</p>
    152         *
    153         * <p>Characters will be chosen from the set of alpha-numeric
    154         * characters as indicated by the arguments.</p>
    155         *
    156         * @param count  the length of random string to create
    157         * @param start  the position in set of chars to start at
    158         * @param end  the position in set of chars to end before
    159         * @param letters  if <code>true</code>, generated string will include
    160         *  alphabetic characters
    161         * @param numbers  if <code>true</code>, generated string will include
    162         *  numeric characters
    163         * @return the random string
    164         */
    165        public static String random(int count, int start, int end, boolean letters, boolean numbers) {
    166            return random(count, start, end, letters, numbers, null, RANDOM);
    167        }
    168
    169        /**
    170         * <p>Creates a random string based on a variety of options, using
    171         * default source of randomness.</p>
    172         *
    173         * <p>This method has exactly the same semantics as
    174         * {@link #random(int,int,int,boolean,boolean,char[],Random)}, but
    175         * instead of using an externally supplied source of randomness, it uses
    176         * the internal static {@link Random} instance.</p>
    177         *
    178         * @param count  the length of random string to create
    179         * @param start  the position in set of chars to start at
    180         * @param end  the position in set of chars to end before
    181         * @param letters  only allow letters?
    182         * @param numbers  only allow numbers?
    183         * @param chars  the set of chars to choose randoms from.
    184         *  If <code>null</code>, then it will use the set of all chars.
    185         * @return the random string
    186         * @throws ArrayIndexOutOfBoundsException if there are not
    187         *  <code>(end - start) + 1</code> characters in the set array.
    188         */
    189        public static String random(int count, int start, int end, boolean letters, boolean numbers, char[] chars) {
    190            return random(count, start, end, letters, numbers, chars, RANDOM);
    191        }
    192
    193        /**
    194         * <p>Creates a random string based on a variety of options, using
    195         * supplied source of randomness.</p>
    196         *
    197         * <p>If start and end are both <code>0</code>, start and end are set
    198         * to <code>' '</code> and <code>'z'</code>, the ASCII printable
    199         * characters, will be used, unless letters and numbers are both
    200         * <code>false</code>, in which case, start and end are set to
    201         * <code>0</code> and <code>Integer.MAX_VALUE</code>.
    202         *
    203         * <p>If set is not <code>null</code>, characters between start and
    204         * end are chosen.</p>
    205         *
    206         * <p>This method accepts a user-supplied {@link Random}
    207         * instance to use as a source of randomness. By seeding a single
    208         * {@link Random} instance with a fixed seed and using it for each call,
    209         * the same random sequence of strings can be generated repeatedly
    210         * and predictably.</p>
    211         *
    212         * @param count  the length of random string to create
    213         * @param start  the position in set of chars to start at
    214         * @param end  the position in set of chars to end before
    215         * @param letters  only allow letters?
    216         * @param numbers  only allow numbers?
    217         * @param chars  the set of chars to choose randoms from.
    218         *  If <code>null</code>, then it will use the set of all chars.
    219         * @param random  a source of randomness.
    220         * @return the random string
    221         * @throws ArrayIndexOutOfBoundsException if there are not
    222         *  <code>(end - start) + 1</code> characters in the set array.
    223         * @throws IllegalArgumentException if <code>count</code> &lt; 0.
    224         * @since 2.0
    225         */
    226        public static String random(int count, int start, int end, boolean letters, boolean numbers,
    227                                    char[] chars, Random random) {
    228            if (count == 0) {
    229                return "";
    230            } else if (count < 0) {
    231                throw new IllegalArgumentException("Requested random string length " + count + " is less than 0.");
    232            }
    233            if ((start == 0) && (end == 0)) {
    234                end = 'z' + 1;
    235                start = ' ';
    236                if (!letters && !numbers) {
    237                    start = 0;
    238                    end = Integer.MAX_VALUE;
    239                }
    240            }
    241
    242            char[] buffer = new char[count];
    243            int gap = end - start;
    244
    245            while (count-- != 0) {
    246                char ch;
    247                if (chars == null) {
    248                    ch = (char) (random.nextInt(gap) + start);
    249                } else {
    250                    ch = chars[random.nextInt(gap) + start];
    251                }
    252                if ((letters && Character.isLetter(ch))
    253                    || (numbers && Character.isDigit(ch))
    254                    || (!letters && !numbers))
    255                {
    256                    if(ch >= 56320 && ch <= 57343) {
    257                        if(count == 0) {
    258                            count++;
    259                        } else {
    260                            // low surrogate, insert high surrogate after putting it in
    261                            buffer[count] = ch;
    262                            count--;
    263                            buffer[count] = (char) (55296 + random.nextInt(128));
    264                        }
    265                    } else if(ch >= 55296 && ch <= 56191) {
    266                        if(count == 0) {
    267                            count++;
    268                        } else {
    269                            // high surrogate, insert low surrogate before putting it in
    270                            buffer[count] = (char) (56320 + random.nextInt(128));
    271                            count--;
    272                            buffer[count] = ch;
    273                        }
    274                    } else if(ch >= 56192 && ch <= 56319) {
    275                        // private high surrogate, no effing clue, so skip it
    276                        count++;
    277                    } else {
    278                        buffer[count] = ch;
    279                    }
    280                } else {
    281                    count++;
    282                }
    283            }
    284            return new String(buffer);
    285        }
    286
    287        /**
    288         * <p>Creates a random string whose length is the number of characters
    289         * specified.</p>
    290         *
    291         * <p>Characters will be chosen from the set of characters
    292         * specified.</p>
    293         *
    294         * @param count  the length of random string to create
    295         * @param chars  the String containing the set of characters to use,
    296         *  may be null
    297         * @return the random string
    298         * @throws IllegalArgumentException if <code>count</code> &lt; 0.
    299         */
    300        public static String random(int count, String chars) {
    301            if (chars == null) {
    302                return random(count, 0, 0, false, false, null, RANDOM);
    303            }
    304            return random(count, chars.toCharArray());
    305        }
    306
    307        /**
    308         * <p>Creates a random string whose length is the number of characters
    309         * specified.</p>
    310         *
    311         * <p>Characters will be chosen from the set of characters specified.</p>
    312         *
    313         * @param count  the length of random string to create
    314         * @param chars  the character array containing the set of characters to use,
    315         *  may be null
    316         * @return the random string
    317         * @throws IllegalArgumentException if <code>count</code> &lt; 0.
    318         */
    319        public static String random(int count, char[] chars) {
    320            if (chars == null) {
    321                return random(count, 0, 0, false, false, null, RANDOM);
    322            }
    323            return random(count, 0, chars.length, false, false, chars, RANDOM);
    324        }
    325
    326    }