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