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     * <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 1056988 2011-01-09 17:58:53Z niallp $
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    }