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    }