1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.lang3;
18
19 import java.util.Random;
20
21 /**
22 * <p>Operations for random {@code String}s.</p>
23 * <p>Currently <em>private high surrogate</em> characters are ignored.
24 * These are Unicode characters that fall between the values 56192 (db80)
25 * and 56319 (dbff) as we don't know how to handle them.
26 * High and low surrogates are correctly dealt with - that is if a
27 * high surrogate is randomly chosen, 55296 (d800) to 56191 (db7f)
28 * then it is followed by a low surrogate. If a low surrogate is chosen,
29 * 56320 (dc00) to 57343 (dfff) then it is placed after a randomly
30 * chosen high surrogate. </p>
31 *
32 * <p>#ThreadSafe#</p>
33 * @since 1.0
34 * @version $Id: RandomStringUtils.java 1436770 2013-01-22 07:09:45Z ggregory $
35 */
36 public class RandomStringUtils {
37
38 /**
39 * <p>Random object used by random method. This has to be not local
40 * to the random method so as to not return the same value in the
41 * same millisecond.</p>
42 */
43 private static final Random RANDOM = new Random();
44
45 /**
46 * <p>{@code RandomStringUtils} instances should NOT be constructed in
47 * standard programming. Instead, the class should be used as
48 * {@code RandomStringUtils.random(5);}.</p>
49 *
50 * <p>This constructor is public to permit tools that require a JavaBean instance
51 * to operate.</p>
52 */
53 public RandomStringUtils() {
54 super();
55 }
56
57 // Random
58 //-----------------------------------------------------------------------
59 /**
60 * <p>Creates a random string whose length is the number of characters
61 * specified.</p>
62 *
63 * <p>Characters will be chosen from the set of all characters.</p>
64 *
65 * @param count the length of random string to create
66 * @return the random string
67 */
68 public static String random(final int count) {
69 return random(count, false, false);
70 }
71
72 /**
73 * <p>Creates a random string whose length is the number of characters
74 * specified.</p>
75 *
76 * <p>Characters will be chosen from the set of characters whose
77 * ASCII value is between {@code 32} and {@code 126} (inclusive).</p>
78 *
79 * @param count the length of random string to create
80 * @return the random string
81 */
82 public static String randomAscii(final int count) {
83 return random(count, 32, 127, false, false);
84 }
85
86 /**
87 * <p>Creates a random string whose length is the number of characters
88 * specified.</p>
89 *
90 * <p>Characters will be chosen from the set of alphabetic
91 * characters.</p>
92 *
93 * @param count the length of random string to create
94 * @return the random string
95 */
96 public static String randomAlphabetic(final int count) {
97 return random(count, true, false);
98 }
99
100 /**
101 * <p>Creates a random string whose length is the number of characters
102 * specified.</p>
103 *
104 * <p>Characters will be chosen from the set of alpha-numeric
105 * characters.</p>
106 *
107 * @param count the length of random string to create
108 * @return the random string
109 */
110 public static String randomAlphanumeric(final int count) {
111 return random(count, true, true);
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 numeric
119 * characters.</p>
120 *
121 * @param count the length of random string to create
122 * @return the random string
123 */
124 public static String randomNumeric(final int count) {
125 return random(count, false, true);
126 }
127
128 /**
129 * <p>Creates a random string whose length is the number of characters
130 * specified.</p>
131 *
132 * <p>Characters will be chosen from the set of alpha-numeric
133 * characters as indicated by the arguments.</p>
134 *
135 * @param count the length of random string to create
136 * @param letters if {@code true}, generated string will include
137 * alphabetic characters
138 * @param numbers if {@code true}, generated string will include
139 * numeric characters
140 * @return the random string
141 */
142 public static String random(final int count, final boolean letters, final boolean numbers) {
143 return random(count, 0, 0, letters, numbers);
144 }
145
146 /**
147 * <p>Creates a random string whose length is the number of characters
148 * specified.</p>
149 *
150 * <p>Characters will be chosen from the set of alpha-numeric
151 * characters as indicated by the arguments.</p>
152 *
153 * @param count the length of random string to create
154 * @param start the position in set of chars to start at
155 * @param end the position in set of chars to end before
156 * @param letters if {@code true}, generated string will include
157 * alphabetic characters
158 * @param numbers if {@code true}, generated string will include
159 * numeric characters
160 * @return the random string
161 */
162 public static String random(final int count, final int start, final int end, final boolean letters, final boolean numbers) {
163 return random(count, start, end, letters, numbers, null, RANDOM);
164 }
165
166 /**
167 * <p>Creates a random string based on a variety of options, using
168 * default source of randomness.</p>
169 *
170 * <p>This method has exactly the same semantics as
171 * {@link #random(int,int,int,boolean,boolean,char[],Random)}, but
172 * instead of using an externally supplied source of randomness, it uses
173 * the internal static {@link Random} instance.</p>
174 *
175 * @param count the length of random string to create
176 * @param start the position in set of chars to start at
177 * @param end the position in set of chars to end before
178 * @param letters only allow letters?
179 * @param numbers only allow numbers?
180 * @param chars the set of chars to choose randoms from.
181 * If {@code null}, then it will use the set of all chars.
182 * @return the random string
183 * @throws ArrayIndexOutOfBoundsException if there are not
184 * {@code (end - start) + 1} characters in the set array.
185 */
186 public static String random(final int count, final int start, final int end, final boolean letters, final boolean numbers, final char... chars) {
187 return random(count, start, end, letters, numbers, chars, RANDOM);
188 }
189
190 /**
191 * <p>Creates a random string based on a variety of options, using
192 * supplied source of randomness.</p>
193 *
194 * <p>If start and end are both {@code 0}, start and end are set
195 * to {@code ' '} and {@code 'z'}, the ASCII printable
196 * characters, will be used, unless letters and numbers are both
197 * {@code false}, in which case, start and end are set to
198 * {@code 0} and {@code Integer.MAX_VALUE}.
199 *
200 * <p>If set is not {@code null}, characters between start and
201 * end are chosen.</p>
202 *
203 * <p>This method accepts a user-supplied {@link Random}
204 * instance to use as a source of randomness. By seeding a single
205 * {@link Random} instance with a fixed seed and using it for each call,
206 * the same random sequence of strings can be generated repeatedly
207 * and predictably.</p>
208 *
209 * @param count the length of random string to create
210 * @param start the position in set of chars to start at
211 * @param end the position in set of chars to end before
212 * @param letters only allow letters?
213 * @param numbers only allow numbers?
214 * @param chars the set of chars to choose randoms from, must not be empty.
215 * If {@code null}, then it will use the set of all chars.
216 * @param random a source of randomness.
217 * @return the random string
218 * @throws ArrayIndexOutOfBoundsException if there are not
219 * {@code (end - start) + 1} characters in the set array.
220 * @throws IllegalArgumentException if {@code count} < 0 or the provided chars array is empty.
221 * @since 2.0
222 */
223 public static String random(int count, int start, int end, final boolean letters, final boolean numbers,
224 final char[] chars, final Random random) {
225 if (count == 0) {
226 return "";
227 } else if (count < 0) {
228 throw new IllegalArgumentException("Requested random string length " + count + " is less than 0.");
229 }
230 if (chars != null && chars.length == 0) {
231 throw new IllegalArgumentException("The chars array must not be empty");
232 }
233
234 if (start == 0 && end == 0) {
235 if (chars != null) {
236 end = chars.length;
237 } else {
238 if (!letters && !numbers) {
239 end = Integer.MAX_VALUE;
240 } else {
241 end = 'z' + 1;
242 start = ' ';
243 }
244 }
245 } else {
246 if (end <= start) {
247 throw new IllegalArgumentException("Parameter end (" + end + ") must be greater than start (" + start + ")");
248 }
249 }
250
251 final char[] buffer = new char[count];
252 final int gap = end - start;
253
254 while (count-- != 0) {
255 char ch;
256 if (chars == null) {
257 ch = (char) (random.nextInt(gap) + start);
258 } else {
259 ch = chars[random.nextInt(gap) + start];
260 }
261 if (letters && Character.isLetter(ch)
262 || numbers && Character.isDigit(ch)
263 || !letters && !numbers) {
264 if(ch >= 56320 && ch <= 57343) {
265 if(count == 0) {
266 count++;
267 } else {
268 // low surrogate, insert high surrogate after putting it in
269 buffer[count] = ch;
270 count--;
271 buffer[count] = (char) (55296 + random.nextInt(128));
272 }
273 } else if(ch >= 55296 && ch <= 56191) {
274 if(count == 0) {
275 count++;
276 } else {
277 // high surrogate, insert low surrogate before putting it in
278 buffer[count] = (char) (56320 + random.nextInt(128));
279 count--;
280 buffer[count] = ch;
281 }
282 } else if(ch >= 56192 && ch <= 56319) {
283 // private high surrogate, no effing clue, so skip it
284 count++;
285 } else {
286 buffer[count] = ch;
287 }
288 } else {
289 count++;
290 }
291 }
292 return new String(buffer);
293 }
294
295 /**
296 * <p>Creates a random string whose length is the number of characters
297 * specified.</p>
298 *
299 * <p>Characters will be chosen from the set of characters
300 * specified by the string, must not be empty.
301 * If null, the set of all characters is used.</p>
302 *
303 * @param count the length of random string to create
304 * @param chars the String containing the set of characters to use,
305 * may be null, but must not be empty
306 * @return the random string
307 * @throws IllegalArgumentException if {@code count} < 0 or the string is empty.
308 */
309 public static String random(final int count, final String chars) {
310 if (chars == null) {
311 return random(count, 0, 0, false, false, null, RANDOM);
312 }
313 return random(count, chars.toCharArray());
314 }
315
316 /**
317 * <p>Creates a random string whose length is the number of characters
318 * specified.</p>
319 *
320 * <p>Characters will be chosen from the set of characters specified.</p>
321 *
322 * @param count the length of random string to create
323 * @param chars the character array containing the set of characters to use,
324 * may be null
325 * @return the random string
326 * @throws IllegalArgumentException if {@code count} < 0.
327 */
328 public static String random(final int count, final char... chars) {
329 if (chars == null) {
330 return random(count, 0, 0, false, false, null, RANDOM);
331 }
332 return random(count, 0, chars.length, false, false, chars, RANDOM);
333 }
334
335 }