Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
StringUtils |
|
| 0.0;0 |
1 | package org.apache.maven.shared.utils; | |
2 | ||
3 | /* | |
4 | * Licensed to the Apache Software Foundation (ASF) under one | |
5 | * or more contributor license agreements. See the NOTICE file | |
6 | * distributed with this work for additional information | |
7 | * regarding copyright ownership. The ASF licenses this file | |
8 | * to you under the Apache License, Version 2.0 (the | |
9 | * "License"); you may not use this file except in compliance | |
10 | * with the License. You may obtain a copy of the License at | |
11 | * | |
12 | * http://www.apache.org/licenses/LICENSE-2.0 | |
13 | * | |
14 | * Unless required by applicable law or agreed to in writing, | |
15 | * software distributed under the License is distributed on an | |
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
17 | * KIND, either express or implied. See the License for the | |
18 | * specific language governing permissions and limitations | |
19 | * under the License. | |
20 | */ | |
21 | ||
22 | ||
23 | import java.util.Arrays; | |
24 | import java.util.Iterator; | |
25 | import java.util.Locale; | |
26 | import java.util.Map; | |
27 | import java.util.StringTokenizer; | |
28 | ||
29 | import javax.annotation.Nonnull; | |
30 | import javax.annotation.Nullable; | |
31 | ||
32 | /** | |
33 | * <p>Common <code>String</code> manipulation routines.</p> | |
34 | * <p/> | |
35 | * <p>Originally from | |
36 | * <a href="http://jakarta.apache.org/turbine/">Turbine</a>, the | |
37 | * GenerationJavaCore library and Velocity. | |
38 | * Later a lots methods from commons-lang StringUtils | |
39 | * got added too. Gradually smaller additions and fixes have been made | |
40 | * over the time by various ASF committers.</p> | |
41 | * | |
42 | * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> | |
43 | * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> | |
44 | * @author <a href="mailto:gcoladonato@yahoo.com">Greg Coladonato</a> | |
45 | * @author <a href="mailto:bayard@generationjava.com">Henri Yandell</a> | |
46 | * @author <a href="mailto:ed@apache.org">Ed Korthof</a> | |
47 | * @author <a href="mailto:rand_mcneely@yahoo.com">Rand McNeely</a> | |
48 | * @author Stephen Colebourne | |
49 | * @author <a href="mailto:fredrik@westermarck.com">Fredrik Westermarck</a> | |
50 | * @author Holger Krauth | |
51 | * @author <a href="mailto:alex@purpletech.com">Alexander Day Chaffee</a> | |
52 | * @version $Id: StringUtils.java 1402496 2012-10-26 13:00:39Z rfscholte $ | |
53 | * | |
54 | */ | |
55 | @SuppressWarnings( "JavaDoc" ) | |
56 | public class StringUtils | |
57 | { | |
58 | /** | |
59 | * <p><code>StringUtils</code> instances should NOT be constructed in | |
60 | * standard programming. Instead, the class should be used as | |
61 | * <code>StringUtils.trim(" foo ");</code>.</p> | |
62 | * <p/> | |
63 | * <p>This constructor is public to permit tools that require a JavaBean | |
64 | * manager to operate.</p> | |
65 | */ | |
66 | public StringUtils() | |
67 | 0 | { |
68 | 0 | } |
69 | ||
70 | // Empty | |
71 | //-------------------------------------------------------------------------- | |
72 | ||
73 | /** | |
74 | * <p>Removes control characters, including whitespace, from both | |
75 | * ends of this String, handling <code>null</code> by returning | |
76 | * an empty String.</p> | |
77 | * | |
78 | * @param str the String to check | |
79 | * @return the trimmed text (never <code>null</code>) | |
80 | * @see java.lang.String#trim() | |
81 | */ | |
82 | public @Nonnull static String clean( String str ) | |
83 | { | |
84 | 4 | return ( str == null ? "" : str.trim() ); |
85 | } | |
86 | ||
87 | /** | |
88 | * <p>Removes control characters, including whitespace, from both | |
89 | * ends of this String, handling <code>null</code> by returning | |
90 | * <code>null</code>.</p> | |
91 | * | |
92 | * @param str the String to check | |
93 | * @return the trimmed text (or <code>null</code>) | |
94 | * @see java.lang.String#trim() | |
95 | */ | |
96 | public static String trim( String str ) | |
97 | { | |
98 | 4 | return ( str == null ? null : str.trim() ); |
99 | } | |
100 | ||
101 | /** | |
102 | * <p>Deletes all whitespaces from a String.</p> | |
103 | * <p/> | |
104 | * <p>Whitespace is defined by | |
105 | * {@link Character#isWhitespace(char)}.</p> | |
106 | * | |
107 | * @param str String target to delete whitespace from | |
108 | * @return the String without whitespaces | |
109 | * @throws NullPointerException | |
110 | */ | |
111 | public @Nonnull static String deleteWhitespace( @Nonnull String str ) | |
112 | { | |
113 | 5 | StringBuilder buffer = new StringBuilder(); |
114 | 5 | int sz = str.length(); |
115 | 32 | for ( int i = 0; i < sz; i++ ) |
116 | { | |
117 | 28 | if ( !Character.isWhitespace( str.charAt( i ) ) ) |
118 | { | |
119 | 11 | buffer.append( str.charAt( i ) ); |
120 | } | |
121 | } | |
122 | 4 | return buffer.toString(); |
123 | } | |
124 | ||
125 | /** | |
126 | * <p>Checks if a String is non <code>null</code> and is | |
127 | * not empty (<code>length > 0</code>).</p> | |
128 | * | |
129 | * @param str the String to check | |
130 | * @return true if the String is non-null, and not length zero | |
131 | */ | |
132 | public static boolean isNotEmpty( String str ) | |
133 | { | |
134 | 7 | return ( ( str != null ) && ( str.length() > 0 ) ); |
135 | } | |
136 | ||
137 | /** | |
138 | * <p>Checks if a (trimmed) String is <code>null</code> or empty.</p> | |
139 | * <p/> | |
140 | * <p><strong>Note:</strong> In future releases, this method will no longer trim the input string such that it works | |
141 | * complementary to {@link #isNotEmpty(String)}. Code that wants to test for whitespace-only strings should be | |
142 | * migrated to use {@link #isBlank(String)} instead.</p> | |
143 | * | |
144 | * @param str the String to check | |
145 | * @return <code>true</code> if the String is <code>null</code>, or | |
146 | * length zero once trimmed | |
147 | */ | |
148 | public static boolean isEmpty( @Nullable String str ) | |
149 | { | |
150 | 25 | return ( ( str == null ) || ( str.trim().length() == 0 ) ); |
151 | } | |
152 | ||
153 | /** | |
154 | * <p> | |
155 | * Checks if a String is whitespace, empty ("") or null. | |
156 | * </p> | |
157 | * <p/> | |
158 | * <pre> | |
159 | * StringUtils.isBlank(null) = true | |
160 | * StringUtils.isBlank("") = true | |
161 | * StringUtils.isBlank(" ") = true | |
162 | * StringUtils.isBlank("bob") = false | |
163 | * StringUtils.isBlank(" bob ") = false | |
164 | * </pre> | |
165 | * | |
166 | * @param str the String to check, may be null | |
167 | * @return <code>true</code> if the String is null, empty or whitespace | |
168 | * | |
169 | */ | |
170 | public static boolean isBlank( @Nullable String str ) | |
171 | { | |
172 | int strLen; | |
173 | 12 | if ( str == null || ( strLen = str.length() ) == 0 ) |
174 | { | |
175 | 2 | return true; |
176 | } | |
177 | 30 | for ( int i = 0; i < strLen; i++ ) |
178 | { | |
179 | 24 | if ( !Character.isWhitespace( str.charAt( i ) ) ) |
180 | { | |
181 | 4 | return false; |
182 | } | |
183 | } | |
184 | 6 | return true; |
185 | } | |
186 | ||
187 | /** | |
188 | * <p> | |
189 | * Checks if a String is not empty (""), not null and not whitespace only. | |
190 | * </p> | |
191 | * <p/> | |
192 | * <pre> | |
193 | * StringUtils.isNotBlank(null) = false | |
194 | * StringUtils.isNotBlank("") = false | |
195 | * StringUtils.isNotBlank(" ") = false | |
196 | * StringUtils.isNotBlank("bob") = true | |
197 | * StringUtils.isNotBlank(" bob ") = true | |
198 | * </pre> | |
199 | * | |
200 | * @param str the String to check, may be null | |
201 | * @return <code>true</code> if the String is not empty and not null and not whitespace | |
202 | * | |
203 | */ | |
204 | public static boolean isNotBlank( @Nullable String str ) | |
205 | { | |
206 | 6 | return !isBlank( str ); |
207 | } | |
208 | ||
209 | // Equals and IndexOf | |
210 | //-------------------------------------------------------------------------- | |
211 | ||
212 | /** | |
213 | * <p>Compares two Strings, returning <code>true</code> if they are equal.</p> | |
214 | * <p/> | |
215 | * <p><code>null</code>s are handled without exceptions. Two <code>null</code> | |
216 | * references are considered to be equal. The comparison is case sensitive.</p> | |
217 | * | |
218 | * @param str1 the first string | |
219 | * @param str2 the second string | |
220 | * @return <code>true</code> if the Strings are equal, case sensitive, or | |
221 | * both <code>null</code> | |
222 | * @see java.lang.String#equals(Object) | |
223 | */ | |
224 | public static boolean equals( @Nullable String str1, @Nullable String str2 ) | |
225 | { | |
226 | 5 | return ( str1 == null ? str2 == null : str1.equals( str2 ) ); |
227 | } | |
228 | ||
229 | /** | |
230 | * <p>Compares two Strings, returning <code>true</code> if they are equal ignoring | |
231 | * the case.</p> | |
232 | * <p/> | |
233 | * <p><code>Nulls</code> are handled without exceptions. Two <code>null</code> | |
234 | * references are considered equal. Comparison is case insensitive.</p> | |
235 | * | |
236 | * @param str1 the first string | |
237 | * @param str2 the second string | |
238 | * @return <code>true</code> if the Strings are equal, case insensitive, or | |
239 | * both <code>null</code> | |
240 | * @see java.lang.String#equalsIgnoreCase(String) | |
241 | */ | |
242 | public static boolean equalsIgnoreCase( String str1, String str2 ) | |
243 | { | |
244 | 6 | return ( str1 == null ? str2 == null : str1.equalsIgnoreCase( str2 ) ); |
245 | } | |
246 | ||
247 | /** | |
248 | * <p>Find the first index of any of a set of potential substrings.</p> | |
249 | * <p/> | |
250 | * <p><code>null</code> String will return <code>-1</code>.</p> | |
251 | * | |
252 | * @param str the String to check | |
253 | * @param searchStrs the Strings to search for | |
254 | * @return the first index of any of the searchStrs in str | |
255 | * @throws NullPointerException if any of searchStrs[i] is <code>null</code> | |
256 | */ | |
257 | public static int indexOfAny( String str, String... searchStrs ) | |
258 | { | |
259 | 4 | if ( ( str == null ) || ( searchStrs == null ) ) |
260 | { | |
261 | 3 | return -1; |
262 | } | |
263 | // String's can't have a MAX_VALUEth index. | |
264 | 1 | int ret = Integer.MAX_VALUE; |
265 | ||
266 | int tmp; | |
267 | 3 | for ( String searchStr : searchStrs ) |
268 | { | |
269 | 2 | tmp = str.indexOf( searchStr ); |
270 | 2 | if ( tmp == -1 ) |
271 | { | |
272 | 1 | continue; |
273 | } | |
274 | ||
275 | 1 | if ( tmp < ret ) |
276 | { | |
277 | 1 | ret = tmp; |
278 | } | |
279 | } | |
280 | ||
281 | 1 | return ( ret == Integer.MAX_VALUE ) ? -1 : ret; |
282 | } | |
283 | ||
284 | /** | |
285 | * <p>Find the latest index of any of a set of potential substrings.</p> | |
286 | * <p/> | |
287 | * <p><code>null</code> string will return <code>-1</code>.</p> | |
288 | * | |
289 | * @param str the String to check | |
290 | * @param searchStrs the Strings to search for | |
291 | * @return the last index of any of the Strings | |
292 | * @throws NullPointerException if any of searchStrs[i] is <code>null</code> | |
293 | */ | |
294 | public static int lastIndexOfAny( String str, String... searchStrs ) | |
295 | { | |
296 | 4 | if ( ( str == null ) || ( searchStrs == null ) ) |
297 | { | |
298 | 2 | return -1; |
299 | } | |
300 | 2 | int ret = -1; |
301 | int tmp; | |
302 | 6 | for ( String searchStr : searchStrs ) |
303 | { | |
304 | 4 | tmp = str.lastIndexOf( searchStr ); |
305 | 4 | if ( tmp > ret ) |
306 | { | |
307 | 1 | ret = tmp; |
308 | } | |
309 | } | |
310 | 2 | return ret; |
311 | } | |
312 | ||
313 | // Substring | |
314 | //-------------------------------------------------------------------------- | |
315 | ||
316 | /** | |
317 | * <p>Gets a substring from the specified string avoiding exceptions.</p> | |
318 | * <p/> | |
319 | * <p>A negative start position can be used to start <code>n</code> | |
320 | * characters from the end of the String.</p> | |
321 | * | |
322 | * @param str the String to get the substring from | |
323 | * @param start the position to start from, negative means | |
324 | * count back from the end of the String by this many characters | |
325 | * @return substring from start position | |
326 | */ | |
327 | public static String substring( String str, int start ) | |
328 | { | |
329 | 5 | if ( str == null ) |
330 | { | |
331 | 2 | return null; |
332 | } | |
333 | ||
334 | // handle negatives, which means last n characters | |
335 | 3 | if ( start < 0 ) |
336 | { | |
337 | 1 | start = str.length() + start; // remember start is negative |
338 | } | |
339 | ||
340 | 3 | if ( start < 0 ) |
341 | { | |
342 | 0 | start = 0; |
343 | } | |
344 | 3 | if ( start > str.length() ) |
345 | { | |
346 | 1 | return ""; |
347 | } | |
348 | ||
349 | 2 | return str.substring( start ); |
350 | } | |
351 | ||
352 | /** | |
353 | * <p>Gets a substring from the specified String avoiding exceptions.</p> | |
354 | * <p/> | |
355 | * <p>A negative start position can be used to start/end <code>n</code> | |
356 | * characters from the end of the String.</p> | |
357 | * | |
358 | * @param str the String to get the substring from | |
359 | * @param start the position to start from, negative means | |
360 | * count back from the end of the string by this many characters | |
361 | * @param end the position to end at (exclusive), negative means | |
362 | * count back from the end of the String by this many characters | |
363 | * @return substring from start position to end positon | |
364 | */ | |
365 | public static String substring( String str, int start, int end ) | |
366 | { | |
367 | 6 | if ( str == null ) |
368 | { | |
369 | 2 | return null; |
370 | } | |
371 | ||
372 | // handle negatives | |
373 | 4 | if ( end < 0 ) |
374 | { | |
375 | 0 | end = str.length() + end; // remember end is negative |
376 | } | |
377 | 4 | if ( start < 0 ) |
378 | { | |
379 | 1 | start = str.length() + start; // remember start is negative |
380 | } | |
381 | ||
382 | // check length next | |
383 | 4 | if ( end > str.length() ) |
384 | { | |
385 | // check this works. | |
386 | 1 | end = str.length(); |
387 | } | |
388 | ||
389 | // if start is greater than end, return "" | |
390 | 4 | if ( start > end ) |
391 | { | |
392 | 2 | return ""; |
393 | } | |
394 | ||
395 | 2 | if ( start < 0 ) |
396 | { | |
397 | 0 | start = 0; |
398 | } | |
399 | 2 | if ( end < 0 ) |
400 | { | |
401 | 0 | end = 0; |
402 | } | |
403 | ||
404 | 2 | return str.substring( start, end ); |
405 | } | |
406 | ||
407 | /** | |
408 | * <p>Gets the leftmost <code>n</code> characters of a String.</p> | |
409 | * <p/> | |
410 | * <p>If <code>n</code> characters are not available, or the | |
411 | * String is <code>null</code>, the String will be returned without | |
412 | * an exception.</p> | |
413 | * | |
414 | * @param str the String to get the leftmost characters from | |
415 | * @param len the length of the required String | |
416 | * @return the leftmost characters | |
417 | * @throws IllegalArgumentException if len is less than zero | |
418 | */ | |
419 | public static String left( String str, int len ) | |
420 | { | |
421 | 5 | if ( len < 0 ) |
422 | { | |
423 | 1 | throw new IllegalArgumentException( "Requested String length " + len + " is less than zero" ); |
424 | } | |
425 | 4 | if ( ( str == null ) || ( str.length() <= len ) ) |
426 | { | |
427 | 2 | return str; |
428 | } | |
429 | else | |
430 | { | |
431 | 2 | return str.substring( 0, len ); |
432 | } | |
433 | } | |
434 | ||
435 | /** | |
436 | * <p>Gets the rightmost <code>n</code> characters of a String.</p> | |
437 | * <p/> | |
438 | * <p>If <code>n</code> characters are not available, or the String | |
439 | * is <code>null</code>, the String will be returned without an | |
440 | * exception.</p> | |
441 | * | |
442 | * @param str the String to get the rightmost characters from | |
443 | * @param len the length of the required String | |
444 | * @return the leftmost characters | |
445 | * @throws IllegalArgumentException if len is less than zero | |
446 | */ | |
447 | public static String right( String str, int len ) | |
448 | { | |
449 | 6 | if ( len < 0 ) |
450 | { | |
451 | 2 | throw new IllegalArgumentException( "Requested String length " + len + " is less than zero" ); |
452 | } | |
453 | 4 | if ( ( str == null ) || ( str.length() <= len ) ) |
454 | { | |
455 | 1 | return str; |
456 | } | |
457 | else | |
458 | { | |
459 | 3 | return str.substring( str.length() - len ); |
460 | } | |
461 | } | |
462 | ||
463 | /** | |
464 | * <p>Gets <code>n</code> characters from the middle of a String.</p> | |
465 | * <p/> | |
466 | * <p>If <code>n</code> characters are not available, the remainder | |
467 | * of the String will be returned without an exception. If the | |
468 | * String is <code>null</code>, <code>null</code> will be returned.</p> | |
469 | * | |
470 | * @param str the String to get the characters from | |
471 | * @param pos the position to start from | |
472 | * @param len the length of the required String | |
473 | * @return the leftmost characters | |
474 | * @throws IndexOutOfBoundsException if pos is out of bounds | |
475 | * @throws IllegalArgumentException if len is less than zero | |
476 | */ | |
477 | public static String mid( String str, int pos, int len ) | |
478 | { | |
479 | 5 | if ( ( pos < 0 ) || ( ( str != null ) && ( pos > str.length() ) ) ) |
480 | { | |
481 | 1 | throw new StringIndexOutOfBoundsException( "String index " + pos + " is out of bounds" ); |
482 | } | |
483 | 4 | if ( len < 0 ) |
484 | { | |
485 | 1 | throw new IllegalArgumentException( "Requested String length " + len + " is less than zero" ); |
486 | } | |
487 | 3 | if ( str == null ) |
488 | { | |
489 | 1 | return null; |
490 | } | |
491 | 2 | if ( str.length() <= ( pos + len ) ) |
492 | { | |
493 | 0 | return str.substring( pos ); |
494 | } | |
495 | else | |
496 | { | |
497 | 2 | return str.substring( pos, pos + len ); |
498 | } | |
499 | } | |
500 | ||
501 | // Splitting | |
502 | //-------------------------------------------------------------------------- | |
503 | ||
504 | /** | |
505 | * <p>Splits the provided text into a array, using whitespace as the | |
506 | * separator.</p> | |
507 | * <p/> | |
508 | * <p>The separator is not included in the returned String array.</p> | |
509 | * | |
510 | * @param str the String to parse | |
511 | * @return an array of parsed Strings | |
512 | */ | |
513 | public @Nonnull static String[] split( @Nonnull String str ) | |
514 | { | |
515 | 3 | return split( str, null, -1 ); |
516 | } | |
517 | ||
518 | /** | |
519 | * @see #split(String, String, int) | |
520 | */ | |
521 | public @Nonnull static String[] split( @Nonnull String text, String separator ) | |
522 | { | |
523 | 50 | return split( text, separator, -1 ); |
524 | } | |
525 | ||
526 | /** | |
527 | * <p>Splits the provided text into a array, based on a given separator.</p> | |
528 | * <p/> | |
529 | * <p>The separator is not included in the returned String array. The | |
530 | * maximum number of splits to perfom can be controlled. A <code>null</code> | |
531 | * separator will cause parsing to be on whitespace.</p> | |
532 | * <p/> | |
533 | * <p>This is useful for quickly splitting a String directly into | |
534 | * an array of tokens, instead of an enumeration of tokens (as | |
535 | * <code>StringTokenizer</code> does).</p> | |
536 | * | |
537 | * @param str The string to parse. | |
538 | * @param separator Characters used as the delimiters. If | |
539 | * <code>null</code>, splits on whitespace. | |
540 | * @param max The maximum number of elements to include in the | |
541 | * array. A zero or negative value implies no limit. | |
542 | * @return an array of parsed Strings | |
543 | */ | |
544 | public @Nonnull static String[] split( @Nonnull String str, String separator, int max ) | |
545 | { | |
546 | StringTokenizer tok; | |
547 | 62 | if ( separator == null ) |
548 | { | |
549 | // Null separator means we're using StringTokenizer's default | |
550 | // delimiter, which comprises all whitespace characters. | |
551 | 11 | tok = new StringTokenizer( str ); |
552 | } | |
553 | else | |
554 | { | |
555 | 51 | tok = new StringTokenizer( str, separator ); |
556 | } | |
557 | ||
558 | 55 | int listSize = tok.countTokens(); |
559 | 55 | if ( ( max > 0 ) && ( listSize > max ) ) |
560 | { | |
561 | 1 | listSize = max; |
562 | } | |
563 | ||
564 | 55 | String[] list = new String[listSize]; |
565 | 55 | int i = 0; |
566 | int lastTokenBegin; | |
567 | 55 | int lastTokenEnd = 0; |
568 | 160 | while ( tok.hasMoreTokens() ) |
569 | { | |
570 | 110 | if ( ( max > 0 ) && ( i == listSize - 1 ) ) |
571 | { | |
572 | // In the situation where we hit the max yet have | |
573 | // tokens left over in our input, the last list | |
574 | // element gets all remaining text. | |
575 | 5 | String endToken = tok.nextToken(); |
576 | 5 | lastTokenBegin = str.indexOf( endToken, lastTokenEnd ); |
577 | 5 | list[i] = str.substring( lastTokenBegin ); |
578 | 5 | break; |
579 | } | |
580 | else | |
581 | { | |
582 | 105 | list[i] = tok.nextToken(); |
583 | 105 | lastTokenBegin = str.indexOf( list[i], lastTokenEnd ); |
584 | 105 | lastTokenEnd = lastTokenBegin + list[i].length(); |
585 | } | |
586 | 105 | i++; |
587 | } | |
588 | 55 | return list; |
589 | } | |
590 | ||
591 | // Joining | |
592 | //-------------------------------------------------------------------------- | |
593 | ||
594 | /** | |
595 | * <p>Concatenates elements of an array into a single String.</p> | |
596 | * <p/> | |
597 | * <p>The difference from join is that concatenate has no delimiter.</p> | |
598 | * | |
599 | * @param array the array of values to concatenate. | |
600 | * @return the concatenated string. | |
601 | */ | |
602 | public @Nonnull static String concatenate( @Nonnull Object... array ) | |
603 | { | |
604 | 4 | return join( array, "" ); |
605 | } | |
606 | ||
607 | /** | |
608 | * <p>Joins the elements of the provided array into a single String | |
609 | * containing the provided list of elements.</p> | |
610 | * <p/> | |
611 | * <p>No delimiter is added before or after the list. A | |
612 | * <code>null</code> separator is the same as a blank String.</p> | |
613 | * | |
614 | * @param array the array of values to join together | |
615 | * @param separator the separator character to use | |
616 | * @return the joined String | |
617 | */ | |
618 | public @Nonnull static String join( @Nonnull Object[] array, String separator ) | |
619 | { | |
620 | 14 | if ( separator == null ) |
621 | { | |
622 | 4 | separator = ""; |
623 | } | |
624 | 14 | int arraySize = array.length; |
625 | 12 | int bufSize = ( arraySize == 0 ? 0 : ( array[0].toString().length() + separator.length() ) * arraySize ); |
626 | 12 | StringBuilder buf = new StringBuilder( bufSize ); |
627 | ||
628 | 64 | for ( int i = 0; i < arraySize; i++ ) |
629 | { | |
630 | 52 | if ( i > 0 ) |
631 | { | |
632 | 43 | buf.append( separator ); |
633 | } | |
634 | 52 | buf.append( array[i] ); |
635 | } | |
636 | 12 | return buf.toString(); |
637 | } | |
638 | ||
639 | /** | |
640 | * <p>Joins the elements of the provided <code>Iterator</code> into | |
641 | * a single String containing the provided elements.</p> | |
642 | * <p/> | |
643 | * <p>No delimiter is added before or after the list. A | |
644 | * <code>null</code> separator is the same as a blank String.</p> | |
645 | * | |
646 | * @param iterator the <code>Iterator</code> of values to join together | |
647 | * @param separator the separator character to use | |
648 | * @return the joined String | |
649 | */ | |
650 | public @Nonnull static String join( @Nonnull Iterator<?> iterator, String separator ) | |
651 | { | |
652 | 10 | if ( separator == null ) |
653 | { | |
654 | 3 | separator = ""; |
655 | } | |
656 | 10 | StringBuilder buf = new StringBuilder( 256 ); // Java default is 16, probably too small |
657 | 34 | while ( iterator.hasNext() ) |
658 | { | |
659 | 24 | buf.append( iterator.next() ); |
660 | 24 | if ( iterator.hasNext() ) |
661 | { | |
662 | 16 | buf.append( separator ); |
663 | } | |
664 | } | |
665 | 9 | return buf.toString(); |
666 | } | |
667 | ||
668 | // Replacing | |
669 | //-------------------------------------------------------------------------- | |
670 | ||
671 | /** | |
672 | * <p>Replace a char with another char inside a larger String, once.</p> | |
673 | * <p/> | |
674 | * <p>A <code>null</code> reference passed to this method is a no-op.</p> | |
675 | * | |
676 | * @param text text to search and replace in | |
677 | * @param repl char to search for | |
678 | * @param with char to replace with | |
679 | * @return the text with any replacements processed | |
680 | * @see #replace(String text, char repl, char with, int max) | |
681 | */ | |
682 | public static String replaceOnce( @Nullable String text, char repl, char with ) | |
683 | { | |
684 | 3 | return replace( text, repl, with, 1 ); |
685 | } | |
686 | ||
687 | /** | |
688 | * <p>Replace all occurances of a char within another char.</p> | |
689 | * <p/> | |
690 | * <p>A <code>null</code> reference passed to this method is a no-op.</p> | |
691 | * | |
692 | * @param text text to search and replace in | |
693 | * @param repl char to search for | |
694 | * @param with char to replace with | |
695 | * @return the text with any replacements processed | |
696 | * @see #replace(String text, char repl, char with, int max) | |
697 | */ | |
698 | public static String replace( @Nullable String text, char repl, char with ) | |
699 | { | |
700 | 4 | return replace( text, repl, with, -1 ); |
701 | } | |
702 | ||
703 | /** | |
704 | * <p>Replace a char with another char inside a larger String, | |
705 | * for the first <code>max</code> values of the search char.</p> | |
706 | * <p/> | |
707 | * <p>A <code>null</code> reference passed to this method is a no-op.</p> | |
708 | * | |
709 | * @param text text to search and replace in | |
710 | * @param repl char to search for | |
711 | * @param with char to replace with | |
712 | * @param max maximum number of values to replace, or <code>-1</code> if no maximum | |
713 | * @return the text with any replacements processed | |
714 | */ | |
715 | public static String replace( @Nullable String text, char repl, char with, int max ) | |
716 | { | |
717 | 13 | return replace( text, String.valueOf( repl ), String.valueOf( with ), max ); |
718 | } | |
719 | ||
720 | /** | |
721 | * <p>Replace a String with another String inside a larger String, once.</p> | |
722 | * <p/> | |
723 | * <p>A <code>null</code> reference passed to this method is a no-op.</p> | |
724 | * | |
725 | * @param text text to search and replace in | |
726 | * @param repl String to search for | |
727 | * @param with String to replace with | |
728 | * @return the text with any replacements processed | |
729 | * @see #replace(String text, String repl, String with, int max) | |
730 | */ | |
731 | public static String replaceOnce( @Nullable String text, @Nullable String repl, @Nullable String with ) | |
732 | { | |
733 | 3 | return replace( text, repl, with, 1 ); |
734 | } | |
735 | ||
736 | /** | |
737 | * <p>Replace all occurances of a String within another String.</p> | |
738 | * <p/> | |
739 | * <p>A <code>null</code> reference passed to this method is a no-op.</p> | |
740 | * | |
741 | * @param text text to search and replace in | |
742 | * @param repl String to search for | |
743 | * @param with String to replace with | |
744 | * @return the text with any replacements processed | |
745 | * @see #replace(String text, String repl, String with, int max) | |
746 | */ | |
747 | public static String replace( @Nullable String text, @Nullable String repl, @Nullable String with ) | |
748 | { | |
749 | 6 | return replace( text, repl, with, -1 ); |
750 | } | |
751 | ||
752 | /** | |
753 | * <p>Replace a String with another String inside a larger String, | |
754 | * for the first <code>max</code> values of the search String.</p> | |
755 | * <p/> | |
756 | * <p>A <code>null</code> reference passed to this method is a no-op.</p> | |
757 | * | |
758 | * @param text text to search and replace in | |
759 | * @param repl String to search for | |
760 | * @param with String to replace with | |
761 | * @param max maximum number of values to replace, or <code>-1</code> if no maximum | |
762 | * @return the text with any replacements processed | |
763 | */ | |
764 | public static String replace( @Nullable String text, @Nullable String repl, @Nullable String with, int max ) | |
765 | { | |
766 | 29 | if ( ( text == null ) || ( repl == null ) || ( with == null ) || ( repl.length() == 0 ) ) |
767 | { | |
768 | 6 | return text; |
769 | } | |
770 | ||
771 | 23 | StringBuilder buf = new StringBuilder( text.length() ); |
772 | 23 | int start = 0, end; |
773 | 46 | while ( ( end = text.indexOf( repl, start ) ) != -1 ) |
774 | { | |
775 | 29 | buf.append( text.substring( start, end ) ).append( with ); |
776 | 29 | start = end + repl.length(); |
777 | ||
778 | 29 | if ( --max == 0 ) |
779 | { | |
780 | 6 | break; |
781 | } | |
782 | } | |
783 | 23 | buf.append( text.substring( start ) ); |
784 | 23 | return buf.toString(); |
785 | } | |
786 | ||
787 | /** | |
788 | * <p>Overlay a part of a String with another String.</p> | |
789 | * | |
790 | * @param text String to do overlaying in | |
791 | * @param overlay String to overlay | |
792 | * @param start int to start overlaying at | |
793 | * @param end int to stop overlaying before | |
794 | * @return String with overlayed text | |
795 | * @throws NullPointerException if text or overlay is <code>null</code> | |
796 | */ | |
797 | @SuppressWarnings( "ConstantConditions" ) | |
798 | public @Nonnull static String overlayString( @Nonnull String text, @Nonnull String overlay, int start, int end ) | |
799 | { | |
800 | 5 | if ( overlay == null ) |
801 | { | |
802 | 2 | throw new NullPointerException( "overlay is null" ); |
803 | } | |
804 | 3 | return text.substring( 0, start ) + overlay + text.substring( end ); |
805 | } | |
806 | ||
807 | // Centering | |
808 | //-------------------------------------------------------------------------- | |
809 | ||
810 | /** | |
811 | * <p>Center a String in a larger String of size <code>n</code>.<p> | |
812 | * <p/> | |
813 | * <p>Uses spaces as the value to buffer the String with. | |
814 | * Equivalent to <code>center(str, size, " ")</code>.</p> | |
815 | * | |
816 | * @param str String to center | |
817 | * @param size int size of new String | |
818 | * @return String containing centered String | |
819 | * @throws NullPointerException if str is <code>null</code> | |
820 | */ | |
821 | public @Nonnull static String center( @Nonnull String str, int size ) | |
822 | { | |
823 | 4 | return center( str, size, " " ); |
824 | } | |
825 | ||
826 | /** | |
827 | * <p>Center a String in a larger String of size <code>n</code>.</p> | |
828 | * <p/> | |
829 | * <p>Uses a supplied String as the value to buffer the String with.</p> | |
830 | * | |
831 | * @param str String to center | |
832 | * @param size int size of new String | |
833 | * @param delim String to buffer the new String with | |
834 | * @return String containing centered String | |
835 | * @throws NullPointerException if str or delim is <code>null</code> | |
836 | * @throws ArithmeticException if delim is the empty String | |
837 | */ | |
838 | public @Nonnull static String center( @Nonnull String str, int size, @Nonnull String delim ) | |
839 | { | |
840 | 8 | int sz = str.length(); |
841 | 6 | int p = size - sz; |
842 | 6 | if ( p < 1 ) |
843 | { | |
844 | 2 | return str; |
845 | } | |
846 | 4 | str = leftPad( str, sz + p / 2, delim ); |
847 | 4 | str = rightPad( str, size, delim ); |
848 | 4 | return str; |
849 | } | |
850 | ||
851 | // Chomping | |
852 | //-------------------------------------------------------------------------- | |
853 | ||
854 | /** | |
855 | * <p>Remove the last newline, and everything after it from a String.</p> | |
856 | * | |
857 | * @param str String to chomp the newline from | |
858 | * @return String without chomped newline | |
859 | * @throws NullPointerException if str is <code>null</code> | |
860 | */ | |
861 | public @Nonnull static String chomp( @Nonnull String str ) | |
862 | { | |
863 | 5 | return chomp( str, "\n" ); |
864 | } | |
865 | ||
866 | /** | |
867 | * <p>Remove the last value of a supplied String, and everything after | |
868 | * it from a String.</p> | |
869 | * | |
870 | * @param str String to chomp from | |
871 | * @param sep String to chomp | |
872 | * @return String without chomped ending | |
873 | * @throws NullPointerException if str or sep is <code>null</code> | |
874 | */ | |
875 | public @Nonnull static String chomp( @Nonnull String str, @Nonnull String sep ) | |
876 | { | |
877 | 10 | int idx = str.lastIndexOf( sep ); |
878 | 8 | if ( idx != -1 ) |
879 | { | |
880 | 6 | return str.substring( 0, idx ); |
881 | } | |
882 | else | |
883 | { | |
884 | 2 | return str; |
885 | } | |
886 | } | |
887 | ||
888 | /** | |
889 | * <p>Remove a newline if and only if it is at the end | |
890 | * of the supplied String.</p> | |
891 | * | |
892 | * @param str String to chomp from | |
893 | * @return String without chomped ending | |
894 | * @throws NullPointerException if str is <code>null</code> | |
895 | */ | |
896 | public @Nonnull static String chompLast( @Nonnull String str ) | |
897 | { | |
898 | 6 | return chompLast( str, "\n" ); |
899 | } | |
900 | ||
901 | /** | |
902 | * <p>Remove a value if and only if the String ends with that value.</p> | |
903 | * | |
904 | * @param str String to chomp from | |
905 | * @param sep String to chomp | |
906 | * @return String without chomped ending | |
907 | * @throws NullPointerException if str or sep is <code>null</code> | |
908 | */ | |
909 | public @Nonnull static String chompLast( @Nonnull String str, @Nonnull String sep ) | |
910 | { | |
911 | 16 | if ( str.length() == 0 ) |
912 | { | |
913 | 0 | return str; |
914 | } | |
915 | 14 | String sub = str.substring( str.length() - sep.length() ); |
916 | 14 | if ( sep.equals( sub ) ) |
917 | { | |
918 | 8 | return str.substring( 0, str.length() - sep.length() ); |
919 | } | |
920 | else | |
921 | { | |
922 | 6 | return str; |
923 | } | |
924 | } | |
925 | ||
926 | /** | |
927 | * <p>Remove everything and return the last value of a supplied String, and | |
928 | * everything after it from a String.</p> | |
929 | * | |
930 | * @param str String to chomp from | |
931 | * @param sep String to chomp | |
932 | * @return String chomped | |
933 | * @throws NullPointerException if str or sep is <code>null</code> | |
934 | */ | |
935 | public @Nonnull static String getChomp( @Nonnull String str, @Nonnull String sep ) | |
936 | { | |
937 | 6 | int idx = str.lastIndexOf( sep ); |
938 | 3 | if ( idx == str.length() - sep.length() ) |
939 | { | |
940 | 1 | return sep; |
941 | } | |
942 | 2 | else if ( idx != -1 ) |
943 | { | |
944 | 1 | return str.substring( idx ); |
945 | } | |
946 | else | |
947 | { | |
948 | 1 | return ""; |
949 | } | |
950 | } | |
951 | ||
952 | /** | |
953 | * <p>Remove the first value of a supplied String, and everything before it | |
954 | * from a String.</p> | |
955 | * | |
956 | * @param str String to chomp from | |
957 | * @param sep String to chomp | |
958 | * @return String without chomped beginning | |
959 | * @throws NullPointerException if str or sep is <code>null</code> | |
960 | */ | |
961 | public @Nonnull static String prechomp( @Nonnull String str, @Nonnull String sep ) | |
962 | { | |
963 | 5 | int idx = str.indexOf( sep ); |
964 | 2 | if ( idx != -1 ) |
965 | { | |
966 | 1 | return str.substring( idx + sep.length() ); |
967 | } | |
968 | else | |
969 | { | |
970 | 1 | return str; |
971 | } | |
972 | } | |
973 | ||
974 | /** | |
975 | * <p>Remove and return everything before the first value of a | |
976 | * supplied String from another String.</p> | |
977 | * | |
978 | * @param str String to chomp from | |
979 | * @param sep String to chomp | |
980 | * @return String prechomped | |
981 | * @throws NullPointerException if str or sep is <code>null</code> | |
982 | */ | |
983 | public @Nonnull static String getPrechomp( @Nonnull String str, String sep ) | |
984 | { | |
985 | 4 | int idx = str.indexOf( sep ); |
986 | 2 | if ( idx != -1 ) |
987 | { | |
988 | 1 | return str.substring( 0, idx + sep.length() ); |
989 | } | |
990 | else | |
991 | { | |
992 | 1 | return ""; |
993 | } | |
994 | } | |
995 | ||
996 | // Chopping | |
997 | //-------------------------------------------------------------------------- | |
998 | ||
999 | /** | |
1000 | * <p>Remove the last character from a String.</p> | |
1001 | * <p/> | |
1002 | * <p>If the String ends in <code>\r\n</code>, then remove both | |
1003 | * of them.</p> | |
1004 | * | |
1005 | * @param str String to chop last character from | |
1006 | * @return String without last character | |
1007 | * @throws NullPointerException if str is <code>null</code> | |
1008 | */ | |
1009 | public @Nonnull static String chop( @Nonnull String str ) | |
1010 | { | |
1011 | 8 | if ( "".equals( str ) ) |
1012 | { | |
1013 | 0 | return ""; |
1014 | } | |
1015 | 8 | if ( str.length() == 1 ) |
1016 | { | |
1017 | 1 | return ""; |
1018 | } | |
1019 | 6 | int lastIdx = str.length() - 1; |
1020 | 6 | String ret = str.substring( 0, lastIdx ); |
1021 | 6 | char last = str.charAt( lastIdx ); |
1022 | 6 | if ( last == '\n' ) |
1023 | { | |
1024 | 2 | if ( ret.charAt( lastIdx - 1 ) == '\r' ) |
1025 | { | |
1026 | 1 | return ret.substring( 0, lastIdx - 1 ); |
1027 | } | |
1028 | } | |
1029 | 5 | return ret; |
1030 | } | |
1031 | ||
1032 | /** | |
1033 | * <p>Remove <code>\n</code> from end of a String if it's there. | |
1034 | * If a <code>\r</code> precedes it, then remove that too.</p> | |
1035 | * | |
1036 | * @param str String to chop a newline from | |
1037 | * @return String without newline | |
1038 | * @throws NullPointerException if str is <code>null</code> | |
1039 | */ | |
1040 | public @Nonnull static String chopNewline( @Nonnull String str ) | |
1041 | { | |
1042 | 6 | int lastIdx = str.length() - 1; |
1043 | 5 | char last = str.charAt( lastIdx ); |
1044 | 5 | if ( last == '\n' ) |
1045 | { | |
1046 | 2 | if ( str.charAt( lastIdx - 1 ) == '\r' ) |
1047 | { | |
1048 | 1 | lastIdx--; |
1049 | } | |
1050 | } | |
1051 | else | |
1052 | { | |
1053 | 3 | lastIdx++; |
1054 | } | |
1055 | 5 | return str.substring( 0, lastIdx ); |
1056 | } | |
1057 | ||
1058 | // Conversion | |
1059 | //-------------------------------------------------------------------------- | |
1060 | ||
1061 | // spec 3.10.6 | |
1062 | ||
1063 | /** | |
1064 | * <p>Escapes any values it finds into their String form.</p> | |
1065 | * <p/> | |
1066 | * <p>So a tab becomes the characters <code>'\\'</code> and | |
1067 | * <code>'t'</code>.</p> | |
1068 | * | |
1069 | * @param str String to escape values in | |
1070 | * @return String with escaped values | |
1071 | * @throws NullPointerException if str is <code>null</code> | |
1072 | */ | |
1073 | public @Nonnull static String escape( @Nonnull String str ) | |
1074 | { | |
1075 | // improved with code from cybertiger@cyberiantiger.org | |
1076 | // unicode from him, and defaul for < 32's. | |
1077 | 4 | int sz = str.length(); |
1078 | 3 | StringBuilder buffer = new StringBuilder( 2 * sz ); |
1079 | 28 | for ( int i = 0; i < sz; i++ ) |
1080 | { | |
1081 | 25 | char ch = str.charAt( i ); |
1082 | ||
1083 | // handle unicode | |
1084 | 25 | if ( ch > 0xfff ) |
1085 | { | |
1086 | 0 | buffer.append( "\\u" ).append( Integer.toHexString( ch ) ); |
1087 | } | |
1088 | 25 | else if ( ch > 0xff ) |
1089 | { | |
1090 | 0 | buffer.append( "\\u0" ).append( Integer.toHexString( ch ) ); |
1091 | } | |
1092 | 25 | else if ( ch > 0x7f ) |
1093 | { | |
1094 | 0 | buffer.append( "\\u00" ).append( Integer.toHexString( ch ) ); |
1095 | } | |
1096 | 25 | else if ( ch < 32 ) |
1097 | { | |
1098 | 2 | switch ( ch ) |
1099 | { | |
1100 | case '\b': | |
1101 | 0 | buffer.append( '\\' ); |
1102 | 0 | buffer.append( 'b' ); |
1103 | 0 | break; |
1104 | case '\n': | |
1105 | 1 | buffer.append( '\\' ); |
1106 | 1 | buffer.append( 'n' ); |
1107 | 1 | break; |
1108 | case '\t': | |
1109 | 1 | buffer.append( '\\' ); |
1110 | 1 | buffer.append( 't' ); |
1111 | 1 | break; |
1112 | case '\f': | |
1113 | 0 | buffer.append( '\\' ); |
1114 | 0 | buffer.append( 'f' ); |
1115 | 0 | break; |
1116 | case '\r': | |
1117 | 0 | buffer.append( '\\' ); |
1118 | 0 | buffer.append( 'r' ); |
1119 | 0 | break; |
1120 | default: | |
1121 | 0 | if ( ch > 0xf ) |
1122 | { | |
1123 | 0 | buffer.append( "\\u00" ).append( Integer.toHexString( ch ) ); |
1124 | } | |
1125 | else | |
1126 | { | |
1127 | 0 | buffer.append( "\\u000" ).append( Integer.toHexString( ch ) ); |
1128 | } | |
1129 | 0 | break; |
1130 | } | |
1131 | } | |
1132 | else | |
1133 | { | |
1134 | 23 | switch ( ch ) |
1135 | { | |
1136 | case '\'': | |
1137 | 0 | buffer.append( '\\' ); |
1138 | 0 | buffer.append( '\'' ); |
1139 | 0 | break; |
1140 | case '"': | |
1141 | 0 | buffer.append( '\\' ); |
1142 | 0 | buffer.append( '"' ); |
1143 | 0 | break; |
1144 | case '\\': | |
1145 | 0 | buffer.append( '\\' ); |
1146 | 0 | buffer.append( '\\' ); |
1147 | 0 | break; |
1148 | default: | |
1149 | 23 | buffer.append( ch ); |
1150 | break; | |
1151 | } | |
1152 | } | |
1153 | } | |
1154 | 3 | return buffer.toString(); |
1155 | } | |
1156 | ||
1157 | // Padding | |
1158 | //-------------------------------------------------------------------------- | |
1159 | ||
1160 | /** | |
1161 | * <p>Repeat a String <code>n</code> times to form a | |
1162 | * new string.</p> | |
1163 | * | |
1164 | * @param str String to repeat | |
1165 | * @param repeat number of times to repeat str | |
1166 | * @return String with repeated String | |
1167 | * @throws NegativeArraySizeException if <code>repeat < 0</code> | |
1168 | * @throws NullPointerException if str is <code>null</code> | |
1169 | */ | |
1170 | public @Nonnull static String repeat( @Nonnull String str, int repeat ) | |
1171 | { | |
1172 | 136 | StringBuilder buffer = new StringBuilder( repeat * str.length() ); |
1173 | 2155 | for ( int i = 0; i < repeat; i++ ) |
1174 | { | |
1175 | 2021 | buffer.append( str ); |
1176 | } | |
1177 | 134 | return buffer.toString(); |
1178 | } | |
1179 | ||
1180 | /** | |
1181 | * <p>Right pad a String with spaces.</p> | |
1182 | * <p/> | |
1183 | * <p>The String is padded to the size of <code>n</code>.</p> | |
1184 | * | |
1185 | * @param str String to repeat | |
1186 | * @param size number of times to repeat str | |
1187 | * @return right padded String | |
1188 | * @throws NullPointerException if str is <code>null</code> | |
1189 | */ | |
1190 | public @Nonnull static String rightPad( @Nonnull String str, int size ) | |
1191 | { | |
1192 | 4 | return rightPad( str, size, " " ); |
1193 | } | |
1194 | ||
1195 | /** | |
1196 | * <p>Right pad a String with a specified string.</p> | |
1197 | * <p/> | |
1198 | * <p>The String is padded to the size of <code>n</code>.</p> | |
1199 | * | |
1200 | * @param str String to pad out | |
1201 | * @param size size to pad to | |
1202 | * @param delim String to pad with | |
1203 | * @return right padded String | |
1204 | * @throws NullPointerException if str or delim is <code>null</code> | |
1205 | * @throws ArithmeticException if delim is the empty String | |
1206 | */ | |
1207 | public @Nonnull static String rightPad( @Nonnull String str, int size, @Nonnull String delim ) | |
1208 | { | |
1209 | 14 | size = ( size - str.length() ) / delim.length(); |
1210 | 10 | if ( size > 0 ) |
1211 | { | |
1212 | 6 | str += repeat( delim, size ); |
1213 | } | |
1214 | 10 | return str; |
1215 | } | |
1216 | ||
1217 | /** | |
1218 | * <p>Left pad a String with spaces.</p> | |
1219 | * <p/> | |
1220 | * <p>The String is padded to the size of <code>n</code>.</p> | |
1221 | * | |
1222 | * @param str String to pad out | |
1223 | * @param size size to pad to | |
1224 | * @return left padded String | |
1225 | * @throws NullPointerException if str or delim is <code>null</code> | |
1226 | */ | |
1227 | public @Nonnull static String leftPad( @Nonnull String str, int size ) | |
1228 | { | |
1229 | 4 | return leftPad( str, size, " " ); |
1230 | } | |
1231 | ||
1232 | /** | |
1233 | * Left pad a String with a specified string. Pad to a size of n. | |
1234 | * | |
1235 | * @param str String to pad out | |
1236 | * @param size size to pad to | |
1237 | * @param delim String to pad with | |
1238 | * @return left padded String | |
1239 | * @throws NullPointerException if str or delim is null | |
1240 | * @throws ArithmeticException if delim is the empty string | |
1241 | */ | |
1242 | public @Nonnull static String leftPad( @Nonnull String str, int size, @Nonnull String delim ) | |
1243 | { | |
1244 | 14 | size = ( size - str.length() ) / delim.length(); |
1245 | 10 | if ( size > 0 ) |
1246 | { | |
1247 | 6 | str = repeat( delim, size ) + str; |
1248 | } | |
1249 | 10 | return str; |
1250 | } | |
1251 | ||
1252 | // Stripping | |
1253 | //-------------------------------------------------------------------------- | |
1254 | ||
1255 | /** | |
1256 | * <p>Remove whitespace from the front and back of a String.</p> | |
1257 | * | |
1258 | * @param str the String to remove whitespace from | |
1259 | * @return the stripped String | |
1260 | */ | |
1261 | public static String strip( String str ) | |
1262 | { | |
1263 | 3 | return strip( str, null ); |
1264 | } | |
1265 | ||
1266 | /** | |
1267 | * <p>Remove a specified String from the front and back of a | |
1268 | * String.</p> | |
1269 | * <p/> | |
1270 | * <p>If whitespace is wanted to be removed, used the | |
1271 | * {@link #strip(java.lang.String)} method.</p> | |
1272 | * | |
1273 | * @param str the String to remove a string from | |
1274 | * @param delim the String to remove at start and end | |
1275 | * @return the stripped String | |
1276 | */ | |
1277 | public static String strip( String str, @Nullable String delim ) | |
1278 | { | |
1279 | 13 | str = stripStart( str, delim ); |
1280 | 13 | return stripEnd( str, delim ); |
1281 | } | |
1282 | ||
1283 | /** | |
1284 | * <p>Strip whitespace from the front and back of every String | |
1285 | * in the array.</p> | |
1286 | * | |
1287 | * @param strs the Strings to remove whitespace from | |
1288 | * @return the stripped Strings | |
1289 | */ | |
1290 | public static String[] stripAll( String... strs ) | |
1291 | { | |
1292 | 4 | return stripAll( strs, null ); |
1293 | } | |
1294 | ||
1295 | /** | |
1296 | * <p>Strip the specified delimiter from the front and back of | |
1297 | * every String in the array.</p> | |
1298 | * | |
1299 | * @param strs the Strings to remove a String from | |
1300 | * @param delimiter the String to remove at start and end | |
1301 | * @return the stripped Strings | |
1302 | */ | |
1303 | public static String[] stripAll( String[] strs, @Nullable String delimiter ) | |
1304 | { | |
1305 | 8 | if ( ( strs == null ) || ( strs.length == 0 ) ) |
1306 | { | |
1307 | 4 | return strs; |
1308 | } | |
1309 | 4 | int sz = strs.length; |
1310 | 4 | String[] newArr = new String[sz]; |
1311 | 10 | for ( int i = 0; i < sz; i++ ) |
1312 | { | |
1313 | 6 | newArr[i] = strip( strs[i], delimiter ); |
1314 | } | |
1315 | 4 | return newArr; |
1316 | } | |
1317 | ||
1318 | /** | |
1319 | * <p>Strip any of a supplied String from the end of a String.</p> | |
1320 | * <p/> | |
1321 | * <p>If the strip String is <code>null</code>, whitespace is | |
1322 | * stripped.</p> | |
1323 | * | |
1324 | * @param str the String to remove characters from | |
1325 | * @param strip the String to remove | |
1326 | * @return the stripped String | |
1327 | */ | |
1328 | public static String stripEnd( String str, @Nullable String strip ) | |
1329 | { | |
1330 | 19 | if ( str == null ) |
1331 | { | |
1332 | 5 | return null; |
1333 | } | |
1334 | 14 | int end = str.length(); |
1335 | ||
1336 | 14 | if ( strip == null ) |
1337 | { | |
1338 | 18 | while ( ( end != 0 ) && Character.isWhitespace( str.charAt( end - 1 ) ) ) |
1339 | { | |
1340 | 11 | end--; |
1341 | } | |
1342 | } | |
1343 | else | |
1344 | { | |
1345 | 12 | while ( ( end != 0 ) && ( strip.indexOf( str.charAt( end - 1 ) ) != -1 ) ) |
1346 | { | |
1347 | 5 | end--; |
1348 | } | |
1349 | } | |
1350 | 14 | return str.substring( 0, end ); |
1351 | } | |
1352 | ||
1353 | /** | |
1354 | * <p>Strip any of a supplied String from the start of a String.</p> | |
1355 | * <p/> | |
1356 | * <p>If the strip String is <code>null</code>, whitespace is | |
1357 | * stripped.</p> | |
1358 | * | |
1359 | * @param str the String to remove characters from | |
1360 | * @param strip the String to remove | |
1361 | * @return the stripped String | |
1362 | */ | |
1363 | public static String stripStart( String str, @Nullable String strip ) | |
1364 | { | |
1365 | 19 | if ( str == null ) |
1366 | { | |
1367 | 5 | return null; |
1368 | } | |
1369 | ||
1370 | 14 | int start = 0; |
1371 | ||
1372 | 14 | int sz = str.length(); |
1373 | ||
1374 | 14 | if ( strip == null ) |
1375 | { | |
1376 | 14 | while ( ( start != sz ) && Character.isWhitespace( str.charAt( start ) ) ) |
1377 | { | |
1378 | 7 | start++; |
1379 | } | |
1380 | } | |
1381 | else | |
1382 | { | |
1383 | 14 | while ( ( start != sz ) && ( strip.indexOf( str.charAt( start ) ) != -1 ) ) |
1384 | { | |
1385 | 7 | start++; |
1386 | } | |
1387 | } | |
1388 | 14 | return str.substring( start ); |
1389 | } | |
1390 | ||
1391 | // Case conversion | |
1392 | //-------------------------------------------------------------------------- | |
1393 | ||
1394 | /** | |
1395 | * <p>Convert a String to upper case, <code>null</code> String | |
1396 | * returns <code>null</code>.</p> | |
1397 | * | |
1398 | * @param str the String to uppercase | |
1399 | * @return the upper cased String | |
1400 | */ | |
1401 | public static String upperCase( String str ) | |
1402 | { | |
1403 | 4 | if ( str == null ) |
1404 | { | |
1405 | 1 | return null; |
1406 | } | |
1407 | 3 | return str.toUpperCase(); |
1408 | } | |
1409 | ||
1410 | /** | |
1411 | * <p>Convert a String to lower case, <code>null</code> String | |
1412 | * returns <code>null</code>.</p> | |
1413 | * | |
1414 | * @param str the string to lowercase | |
1415 | * @return the lower cased String | |
1416 | */ | |
1417 | public static String lowerCase( String str ) | |
1418 | { | |
1419 | 3 | if ( str == null ) |
1420 | { | |
1421 | 1 | return null; |
1422 | } | |
1423 | 2 | return str.toLowerCase(); |
1424 | } | |
1425 | ||
1426 | /** | |
1427 | * <p>Uncapitalise a String.</p> | |
1428 | * <p/> | |
1429 | * <p>That is, convert the first character into lower-case. | |
1430 | * <code>null</code> is returned as <code>null</code>.</p> | |
1431 | * | |
1432 | * @param str the String to uncapitalise | |
1433 | * @return uncapitalised String | |
1434 | */ | |
1435 | public static String uncapitalise( String str ) | |
1436 | { | |
1437 | 5 | if ( str == null ) |
1438 | { | |
1439 | 1 | return null; |
1440 | } | |
1441 | 4 | else if ( str.length() == 0 ) |
1442 | { | |
1443 | 0 | return ""; |
1444 | } | |
1445 | else | |
1446 | { | |
1447 | 4 | return String.valueOf( Character.toLowerCase( str.charAt( 0 ) ) ) + str.substring( 1 ); |
1448 | } | |
1449 | } | |
1450 | ||
1451 | /** | |
1452 | * <p>Capitalise a String.</p> | |
1453 | * <p/> | |
1454 | * <p>That is, convert the first character into title-case. | |
1455 | * <code>null</code> is returned as <code>null</code>.</p> | |
1456 | * | |
1457 | * @param str the String to capitalise | |
1458 | * @return capitalised String | |
1459 | */ | |
1460 | public static String capitalise( String str ) | |
1461 | { | |
1462 | 2 | if ( str == null ) |
1463 | { | |
1464 | 1 | return null; |
1465 | } | |
1466 | 1 | else if ( str.length() == 0 ) |
1467 | { | |
1468 | 0 | return ""; |
1469 | } | |
1470 | else | |
1471 | { | |
1472 | 1 | return String.valueOf( Character.toTitleCase( str.charAt( 0 ) ) ) + str.substring( 1 ); |
1473 | } | |
1474 | } | |
1475 | ||
1476 | /** | |
1477 | * <p>Swaps the case of String.</p> | |
1478 | * <p/> | |
1479 | * <p>Properly looks after making sure the start of words | |
1480 | * are Titlecase and not Uppercase.</p> | |
1481 | * <p/> | |
1482 | * <p><code>null</code> is returned as <code>null</code>.</p> | |
1483 | * | |
1484 | * @param str the String to swap the case of | |
1485 | * @return the modified String | |
1486 | */ | |
1487 | public static String swapCase( String str ) | |
1488 | { | |
1489 | 3 | if ( str == null ) |
1490 | { | |
1491 | 1 | return null; |
1492 | } | |
1493 | 2 | int sz = str.length(); |
1494 | 2 | StringBuilder buffer = new StringBuilder( sz ); |
1495 | ||
1496 | 2 | boolean whitespace = false; |
1497 | char ch; | |
1498 | char tmp; | |
1499 | ||
1500 | 12 | for ( int i = 0; i < sz; i++ ) |
1501 | { | |
1502 | 10 | ch = str.charAt( i ); |
1503 | 10 | if ( Character.isUpperCase( ch ) ) |
1504 | { | |
1505 | 2 | tmp = Character.toLowerCase( ch ); |
1506 | } | |
1507 | 8 | else if ( Character.isTitleCase( ch ) ) |
1508 | { | |
1509 | 0 | tmp = Character.toLowerCase( ch ); |
1510 | } | |
1511 | 8 | else if ( Character.isLowerCase( ch ) ) |
1512 | { | |
1513 | 8 | if ( whitespace ) |
1514 | { | |
1515 | 0 | tmp = Character.toTitleCase( ch ); |
1516 | } | |
1517 | else | |
1518 | { | |
1519 | 8 | tmp = Character.toUpperCase( ch ); |
1520 | } | |
1521 | } | |
1522 | else | |
1523 | { | |
1524 | 0 | tmp = ch; |
1525 | } | |
1526 | 10 | buffer.append( tmp ); |
1527 | 10 | whitespace = Character.isWhitespace( ch ); |
1528 | } | |
1529 | 2 | return buffer.toString(); |
1530 | } | |
1531 | ||
1532 | ||
1533 | /** | |
1534 | * <p>Capitalise all the words in a String.</p> | |
1535 | * <p/> | |
1536 | * <p>Uses {@link Character#isWhitespace(char)} as a | |
1537 | * separator between words.</p> | |
1538 | * <p/> | |
1539 | * <p><code>null</code> will return <code>null</code>.</p> | |
1540 | * | |
1541 | * @param str the String to capitalise | |
1542 | * @return capitalised String | |
1543 | */ | |
1544 | public static String capitaliseAllWords( String str ) | |
1545 | { | |
1546 | 2 | if ( str == null ) |
1547 | { | |
1548 | 1 | return null; |
1549 | } | |
1550 | 1 | int sz = str.length(); |
1551 | 1 | StringBuilder buffer = new StringBuilder( sz ); |
1552 | 1 | boolean space = true; |
1553 | 14 | for ( int i = 0; i < sz; i++ ) |
1554 | { | |
1555 | 13 | char ch = str.charAt( i ); |
1556 | 13 | if ( Character.isWhitespace( ch ) ) |
1557 | { | |
1558 | 2 | buffer.append( ch ); |
1559 | 2 | space = true; |
1560 | } | |
1561 | 11 | else if ( space ) |
1562 | { | |
1563 | 3 | buffer.append( Character.toTitleCase( ch ) ); |
1564 | 3 | space = false; |
1565 | } | |
1566 | else | |
1567 | { | |
1568 | 8 | buffer.append( ch ); |
1569 | } | |
1570 | } | |
1571 | 1 | return buffer.toString(); |
1572 | } | |
1573 | ||
1574 | /** | |
1575 | * <p>Uncapitalise all the words in a string.</p> | |
1576 | * <p/> | |
1577 | * <p>Uses {@link Character#isWhitespace(char)} as a | |
1578 | * separator between words.</p> | |
1579 | * <p/> | |
1580 | * <p><code>null</code> will return <code>null</code>.</p> | |
1581 | * | |
1582 | * @param str the string to uncapitalise | |
1583 | * @return uncapitalised string | |
1584 | */ | |
1585 | public static String uncapitaliseAllWords( String str ) | |
1586 | { | |
1587 | 5 | if ( str == null ) |
1588 | { | |
1589 | 1 | return null; |
1590 | } | |
1591 | 4 | int sz = str.length(); |
1592 | 4 | StringBuilder buffer = new StringBuilder( sz ); |
1593 | 4 | boolean space = true; |
1594 | 37 | for ( int i = 0; i < sz; i++ ) |
1595 | { | |
1596 | 33 | char ch = str.charAt( i ); |
1597 | 33 | if ( Character.isWhitespace( ch ) ) |
1598 | { | |
1599 | 6 | buffer.append( ch ); |
1600 | 6 | space = true; |
1601 | } | |
1602 | 27 | else if ( space ) |
1603 | { | |
1604 | 6 | buffer.append( Character.toLowerCase( ch ) ); |
1605 | 6 | space = false; |
1606 | } | |
1607 | else | |
1608 | { | |
1609 | 21 | buffer.append( ch ); |
1610 | } | |
1611 | } | |
1612 | 4 | return buffer.toString(); |
1613 | } | |
1614 | ||
1615 | // Nested extraction | |
1616 | //-------------------------------------------------------------------------- | |
1617 | ||
1618 | /** | |
1619 | * <p>Get the String that is nested in between two instances of the | |
1620 | * same String.</p> | |
1621 | * <p/> | |
1622 | * <p>If <code>str</code> is <code>null</code>, will | |
1623 | * return <code>null</code>.</p> | |
1624 | * | |
1625 | * @param str the String containing nested-string | |
1626 | * @param tag the String before and after nested-string | |
1627 | * @return the String that was nested, or <code>null</code> | |
1628 | * @throws NullPointerException if tag is <code>null</code> | |
1629 | */ | |
1630 | public static String getNestedString( String str, @Nonnull String tag ) | |
1631 | { | |
1632 | 4 | return getNestedString( str, tag, tag ); |
1633 | } | |
1634 | ||
1635 | /** | |
1636 | * <p>Get the String that is nested in between two Strings.</p> | |
1637 | * | |
1638 | * @param str the String containing nested-string | |
1639 | * @param open the String before nested-string | |
1640 | * @param close the String after nested-string | |
1641 | * @return the String that was nested, or <code>null</code> | |
1642 | * @throws NullPointerException if open or close is <code>null</code> | |
1643 | */ | |
1644 | public static String getNestedString( String str, @Nonnull String open, @Nonnull String close ) | |
1645 | { | |
1646 | 10 | if ( str == null ) |
1647 | { | |
1648 | 2 | return null; |
1649 | } | |
1650 | 8 | int start = str.indexOf( open ); |
1651 | 5 | if ( start != -1 ) |
1652 | { | |
1653 | 2 | int end = str.indexOf( close, start + open.length() ); |
1654 | 2 | if ( end != -1 ) |
1655 | { | |
1656 | 2 | return str.substring( start + open.length(), end ); |
1657 | } | |
1658 | } | |
1659 | 3 | return null; |
1660 | } | |
1661 | ||
1662 | /** | |
1663 | * <p>How many times is the substring in the larger String.</p> | |
1664 | * <p/> | |
1665 | * <p><code>null</code> returns <code>0</code>.</p> | |
1666 | * | |
1667 | * @param str the String to check | |
1668 | * @param sub the substring to count | |
1669 | * @return the number of occurances, 0 if the String is <code>null</code> | |
1670 | * @throws NullPointerException if sub is <code>null</code> | |
1671 | */ | |
1672 | public static int countMatches( @Nullable String str, @Nonnull String sub ) | |
1673 | { | |
1674 | 17 | if ( sub.equals( "" ) ) |
1675 | { | |
1676 | 0 | return 0; |
1677 | } | |
1678 | 15 | if ( str == null ) |
1679 | { | |
1680 | 1 | return 0; |
1681 | } | |
1682 | 14 | int count = 0; |
1683 | 14 | int idx = 0; |
1684 | 63 | while ( ( idx = str.indexOf( sub, idx ) ) != -1 ) |
1685 | { | |
1686 | 49 | count++; |
1687 | 49 | idx += sub.length(); |
1688 | } | |
1689 | 14 | return count; |
1690 | } | |
1691 | ||
1692 | // Character Tests | |
1693 | //-------------------------------------------------------------------------- | |
1694 | ||
1695 | /** | |
1696 | * <p>Checks if the String contains only unicode letters.</p> | |
1697 | * <p/> | |
1698 | * <p><code>null</code> will return <code>false</code>. | |
1699 | * An empty String will return <code>true</code>.</p> | |
1700 | * | |
1701 | * @param str the String to check | |
1702 | * @return <code>true</code> if only contains letters, and is non-null | |
1703 | */ | |
1704 | public static boolean isAlpha( String str ) | |
1705 | { | |
1706 | 5 | if ( str == null ) |
1707 | { | |
1708 | 1 | return false; |
1709 | } | |
1710 | 4 | int sz = str.length(); |
1711 | 22 | for ( int i = 0; i < sz; i++ ) |
1712 | { | |
1713 | 21 | if ( !Character.isLetter( str.charAt( i ) ) ) |
1714 | { | |
1715 | 3 | return false; |
1716 | } | |
1717 | } | |
1718 | 1 | return true; |
1719 | } | |
1720 | ||
1721 | /** | |
1722 | * <p>Checks if the String contains only whitespace.</p> | |
1723 | * <p/> | |
1724 | * <p><code>null</code> will return <code>false</code>. An | |
1725 | * empty String will return <code>true</code>.</p> | |
1726 | * | |
1727 | * @param str the String to check | |
1728 | * @return <code>true</code> if only contains whitespace, and is non-null | |
1729 | */ | |
1730 | public static boolean isWhitespace( String str ) | |
1731 | { | |
1732 | 7 | if ( str == null ) |
1733 | { | |
1734 | 1 | return false; |
1735 | } | |
1736 | 6 | int sz = str.length(); |
1737 | 16 | for ( int i = 0; i < sz; i++ ) |
1738 | { | |
1739 | 12 | if ( ( !Character.isWhitespace( str.charAt( i ) ) ) ) |
1740 | { | |
1741 | 2 | return false; |
1742 | } | |
1743 | } | |
1744 | 4 | return true; |
1745 | } | |
1746 | ||
1747 | /** | |
1748 | * <p>Checks if the String contains only unicode letters and | |
1749 | * space (<code>' '</code>).</p> | |
1750 | * <p/> | |
1751 | * <p><code>null</code> will return <code>false</code>. An | |
1752 | * empty String will return <code>true</code>.</p> | |
1753 | * | |
1754 | * @param str the String to check | |
1755 | * @return <code>true</code> if only contains letters and space, | |
1756 | * and is non-null | |
1757 | */ | |
1758 | public static boolean isAlphaSpace( String str ) | |
1759 | { | |
1760 | 6 | if ( str == null ) |
1761 | { | |
1762 | 1 | return false; |
1763 | } | |
1764 | 5 | int sz = str.length(); |
1765 | 35 | for ( int i = 0; i < sz; i++ ) |
1766 | { | |
1767 | 33 | if ( ( !Character.isLetter( str.charAt( i ) ) ) && ( str.charAt( i ) != ' ' ) ) |
1768 | { | |
1769 | 3 | return false; |
1770 | } | |
1771 | } | |
1772 | 2 | return true; |
1773 | } | |
1774 | ||
1775 | /** | |
1776 | * <p>Checks if the String contains only unicode letters or digits.</p> | |
1777 | * <p/> | |
1778 | * <p><code>null</code> will return <code>false</code>. An empty | |
1779 | * String will return <code>true</code>.</p> | |
1780 | * | |
1781 | * @param str the String to check | |
1782 | * @return <code>true</code> if only contains letters or digits, | |
1783 | * and is non-null | |
1784 | */ | |
1785 | public static boolean isAlphanumeric( String str ) | |
1786 | { | |
1787 | 9 | if ( str == null ) |
1788 | { | |
1789 | 1 | return false; |
1790 | } | |
1791 | 8 | int sz = str.length(); |
1792 | 62 | for ( int i = 0; i < sz; i++ ) |
1793 | { | |
1794 | 58 | if ( !Character.isLetterOrDigit( str.charAt( i ) ) ) |
1795 | { | |
1796 | 4 | return false; |
1797 | } | |
1798 | } | |
1799 | 4 | return true; |
1800 | } | |
1801 | ||
1802 | /** | |
1803 | * <p>Checks if the String contains only unicode letters, digits | |
1804 | * or space (<code>' '</code>).</p> | |
1805 | * <p/> | |
1806 | * <p><code>null</code> will return <code>false</code>. An empty | |
1807 | * String will return <code>true</code>.</p> | |
1808 | * | |
1809 | * @param str the String to check | |
1810 | * @return <code>true</code> if only contains letters, digits or space, | |
1811 | * and is non-null | |
1812 | */ | |
1813 | public static boolean isAlphanumericSpace( String str ) | |
1814 | { | |
1815 | 9 | if ( str == null ) |
1816 | { | |
1817 | 1 | return false; |
1818 | } | |
1819 | 8 | int sz = str.length(); |
1820 | 66 | for ( int i = 0; i < sz; i++ ) |
1821 | { | |
1822 | 60 | if ( ( !Character.isLetterOrDigit( str.charAt( i ) ) ) && ( str.charAt( i ) != ' ' ) ) |
1823 | { | |
1824 | 2 | return false; |
1825 | } | |
1826 | } | |
1827 | 6 | return true; |
1828 | } | |
1829 | ||
1830 | /** | |
1831 | * <p>Checks if the String contains only unicode digits.</p> | |
1832 | * <p/> | |
1833 | * <p><code>null</code> will return <code>false</code>. | |
1834 | * An empty String will return <code>true</code>.</p> | |
1835 | * | |
1836 | * @param str the String to check | |
1837 | * @return <code>true</code> if only contains digits, and is non-null | |
1838 | */ | |
1839 | public static boolean isNumeric( String str ) | |
1840 | { | |
1841 | 9 | if ( str == null ) |
1842 | { | |
1843 | 1 | return false; |
1844 | } | |
1845 | 8 | int sz = str.length(); |
1846 | 21 | for ( int i = 0; i < sz; i++ ) |
1847 | { | |
1848 | 19 | if ( !Character.isDigit( str.charAt( i ) ) ) |
1849 | { | |
1850 | 6 | return false; |
1851 | } | |
1852 | } | |
1853 | 2 | return true; |
1854 | } | |
1855 | ||
1856 | // Defaults | |
1857 | //-------------------------------------------------------------------------- | |
1858 | ||
1859 | /** | |
1860 | * <p>Returns either the passed in <code>Object</code> as a String, | |
1861 | * or, if the <code>Object</code> is <code>null</code>, an empty | |
1862 | * String.</p> | |
1863 | * | |
1864 | * @param obj the Object to check | |
1865 | * @return the passed in Object's toString, or blank if it was | |
1866 | * <code>null</code> | |
1867 | */ | |
1868 | public @Nonnull static String defaultString( Object obj ) | |
1869 | { | |
1870 | 2 | return defaultString( obj, "" ); |
1871 | } | |
1872 | ||
1873 | /** | |
1874 | * <p>Returns either the passed in <code>Object</code> as a String, | |
1875 | * or, if the <code>Object</code> is <code>null</code>, a passed | |
1876 | * in default String.</p> | |
1877 | * | |
1878 | * @param obj the Object to check | |
1879 | * @param defaultString the default String to return if str is | |
1880 | * <code>null</code> | |
1881 | * @return the passed in string, or the default if it was | |
1882 | * <code>null</code> | |
1883 | */ | |
1884 | public @Nonnull static String defaultString( Object obj, @Nonnull String defaultString ) | |
1885 | { | |
1886 | 4 | return ( obj == null ) ? defaultString : obj.toString(); |
1887 | } | |
1888 | ||
1889 | // Reversing | |
1890 | //-------------------------------------------------------------------------- | |
1891 | ||
1892 | /** | |
1893 | * <p>Reverse a String.</p> | |
1894 | * <p/> | |
1895 | * <p><code>null</code> String returns <code>null</code>.</p> | |
1896 | * | |
1897 | * @param str the String to reverse | |
1898 | * @return the reversed String | |
1899 | */ | |
1900 | public static String reverse( String str ) | |
1901 | { | |
1902 | 4 | if ( str == null ) |
1903 | { | |
1904 | 1 | return null; |
1905 | } | |
1906 | 3 | return new StringBuffer( str ).reverse().toString(); |
1907 | } | |
1908 | ||
1909 | /** | |
1910 | * <p>Reverses a String that is delimited by a specific character.</p> | |
1911 | * <p/> | |
1912 | * <p>The Strings between the delimiters are not reversed. | |
1913 | * Thus java.lang.String becomes String.lang.java (if the delimiter | |
1914 | * is <code>'.'</code>).</p> | |
1915 | * | |
1916 | * @param str the String to reverse | |
1917 | * @param delimiter the delimiter to use | |
1918 | * @return the reversed String | |
1919 | */ | |
1920 | public @Nonnull static String reverseDelimitedString( @Nonnull String str, String delimiter ) | |
1921 | { | |
1922 | // could implement manually, but simple way is to reuse other, | |
1923 | // probably slower, methods. | |
1924 | 7 | String[] strs = split( str, delimiter ); |
1925 | 5 | reverseArray( strs ); |
1926 | 5 | return join( strs, delimiter ); |
1927 | } | |
1928 | ||
1929 | /** | |
1930 | * <p>Reverses an array.</p> | |
1931 | * <p/> | |
1932 | * <p>TAKEN FROM CollectionsUtils.</p> | |
1933 | * | |
1934 | * @param array the array to reverse | |
1935 | */ | |
1936 | private static void reverseArray( @Nonnull String... array ) | |
1937 | { | |
1938 | 5 | int i = 0; |
1939 | 5 | int j = array.length - 1; |
1940 | String tmp; | |
1941 | ||
1942 | 6 | while ( j > i ) |
1943 | { | |
1944 | 1 | tmp = array[j]; |
1945 | 1 | array[j] = array[i]; |
1946 | 1 | array[i] = tmp; |
1947 | 1 | j--; |
1948 | 1 | i++; |
1949 | } | |
1950 | 5 | } |
1951 | ||
1952 | // Abbreviating | |
1953 | //-------------------------------------------------------------------------- | |
1954 | ||
1955 | /** | |
1956 | * Turn "Now is the time for all good men" into "Now is the time for..." | |
1957 | * <p/> | |
1958 | * Specifically: | |
1959 | * <p/> | |
1960 | * If str is less than max characters long, return it. | |
1961 | * Else abbreviate it to (substring(str, 0, max-3) + "..."). | |
1962 | * If maxWidth is less than 3, throw an IllegalArgumentException. | |
1963 | * In no case will it return a string of length greater than maxWidth. | |
1964 | * | |
1965 | * @param maxWidth maximum length of result string | |
1966 | */ | |
1967 | public @Nonnull static String abbreviate( @Nonnull String s, int maxWidth ) | |
1968 | { | |
1969 | 5 | return abbreviate( s, 0, maxWidth ); |
1970 | } | |
1971 | ||
1972 | /** | |
1973 | * Turn "Now is the time for all good men" into "...is the time for..." | |
1974 | * <p/> | |
1975 | * Works like abbreviate(String, int), but allows you to specify a "left edge" | |
1976 | * offset. Note that this left edge is not necessarily going to be the leftmost | |
1977 | * character in the result, or the first | |
1978 | * character following the ellipses, but it will appear somewhere in the result. | |
1979 | * In no case will it return a string of length greater than maxWidth. | |
1980 | * | |
1981 | * @param offset left edge of source string | |
1982 | * @param maxWidth maximum length of result string | |
1983 | */ | |
1984 | public @Nonnull static String abbreviate( @Nonnull String s, int offset, int maxWidth ) | |
1985 | { | |
1986 | 10 | if ( maxWidth < 4 ) |
1987 | { | |
1988 | 2 | throw new IllegalArgumentException( "Minimum abbreviation width is 4" ); |
1989 | } | |
1990 | 8 | if ( s.length() <= maxWidth ) |
1991 | { | |
1992 | 3 | return s; |
1993 | } | |
1994 | 3 | if ( offset > s.length() ) |
1995 | { | |
1996 | 0 | offset = s.length(); |
1997 | } | |
1998 | 3 | if ( ( s.length() - offset ) < ( maxWidth - 3 ) ) |
1999 | { | |
2000 | 0 | offset = s.length() - ( maxWidth - 3 ); |
2001 | } | |
2002 | 3 | if ( offset <= 4 ) |
2003 | { | |
2004 | 2 | return s.substring( 0, maxWidth - 3 ) + "..."; |
2005 | } | |
2006 | 1 | if ( maxWidth < 7 ) |
2007 | { | |
2008 | 0 | throw new IllegalArgumentException( "Minimum abbreviation width with offset is 7" ); |
2009 | } | |
2010 | 1 | if ( ( offset + ( maxWidth - 3 ) ) < s.length() ) |
2011 | { | |
2012 | 1 | return "..." + abbreviate( s.substring( offset ), maxWidth - 3 ); |
2013 | } | |
2014 | 0 | return "..." + s.substring( s.length() - ( maxWidth - 3 ) ); |
2015 | } | |
2016 | ||
2017 | // Difference | |
2018 | //-------------------------------------------------------------------------- | |
2019 | ||
2020 | /** | |
2021 | * Compare two strings, and return the portion where they differ. | |
2022 | * (More precisely, return the remainder of the second string, | |
2023 | * starting from where it's different from the first.) | |
2024 | * <p/> | |
2025 | * E.g. strdiff("i am a machine", "i am a robot") -> "robot" | |
2026 | * | |
2027 | * @return the portion of s2 where it differs from s1; returns the empty string ("") if they are equal | |
2028 | */ | |
2029 | public static String difference( @Nonnull String s1, @Nonnull String s2 ) | |
2030 | { | |
2031 | 6 | int at = differenceAt( s1, s2 ); |
2032 | 3 | if ( at == -1 ) |
2033 | { | |
2034 | 0 | return ""; |
2035 | } | |
2036 | 3 | return s2.substring( at ); |
2037 | } | |
2038 | ||
2039 | /** | |
2040 | * Compare two strings, and return the index at which the strings begin to differ. | |
2041 | * <p> | |
2042 | * E.g. strdiff("i am a machine", "i am a robot") -> 7 | |
2043 | * </p> | |
2044 | * | |
2045 | * @return the index where s2 and s1 begin to differ; -1 if they are equal | |
2046 | */ | |
2047 | public static int differenceAt( @Nonnull String s1, @Nonnull String s2 ) | |
2048 | { | |
2049 | int i; | |
2050 | 26 | for ( i = 0; ( i < s1.length() ) && ( i < s2.length() ); ++i ) |
2051 | { | |
2052 | 20 | if ( s1.charAt( i ) != s2.charAt( i ) ) |
2053 | { | |
2054 | 6 | break; |
2055 | } | |
2056 | } | |
2057 | 6 | if ( ( i < s2.length() ) || ( i < s1.length() ) ) |
2058 | { | |
2059 | 6 | return i; |
2060 | } | |
2061 | 0 | return -1; |
2062 | } | |
2063 | ||
2064 | /** | |
2065 | * Fill all 'variables' in the given text with the values from the map. | |
2066 | * Any text looking like '${key}' will get replaced by the value stored | |
2067 | * in the namespace map under the 'key'. | |
2068 | * | |
2069 | * @param text | |
2070 | * @param namespace | |
2071 | * @return the interpolated text. | |
2072 | */ | |
2073 | public static String interpolate( String text, @Nonnull Map<?, ?> namespace ) | |
2074 | { | |
2075 | 4 | for ( Map.Entry<?, ?> entry : namespace.entrySet() ) |
2076 | { | |
2077 | 1 | String key = entry.getKey().toString(); |
2078 | ||
2079 | 1 | Object obj = entry.getValue(); |
2080 | ||
2081 | 1 | if ( obj == null ) |
2082 | { | |
2083 | 0 | throw new NullPointerException( "The value of the key '" + key + "' is null." ); |
2084 | } | |
2085 | ||
2086 | 1 | String value = obj.toString(); |
2087 | ||
2088 | 1 | text = replace( text, "${" + key + "}", value ); |
2089 | ||
2090 | 1 | if ( !key.contains( " " ) ) |
2091 | { | |
2092 | 1 | text = replace( text, "$" + key, value ); |
2093 | } | |
2094 | 1 | } |
2095 | 2 | return text; |
2096 | } | |
2097 | ||
2098 | /** | |
2099 | * This is basically the inverse of {@link #addAndDeHump(String)}. | |
2100 | * It will remove the 'replaceThis' parameter and uppercase the next | |
2101 | * character afterwards. | |
2102 | * <pre> | |
2103 | * removeAndHump( "this-is-it", %quot;-" ); | |
2104 | * </pre> | |
2105 | * will become 'ThisIsIt'. | |
2106 | * | |
2107 | * @param data | |
2108 | * @param replaceThis | |
2109 | * @return humped String | |
2110 | */ | |
2111 | public @Nonnull static String removeAndHump( @Nonnull String data, @Nonnull String replaceThis ) | |
2112 | { | |
2113 | String temp; | |
2114 | ||
2115 | 6 | StringBuilder out = new StringBuilder(); |
2116 | ||
2117 | 6 | temp = data; |
2118 | ||
2119 | 6 | StringTokenizer st = new StringTokenizer( temp, replaceThis ); |
2120 | ||
2121 | 11 | while ( st.hasMoreTokens() ) |
2122 | { | |
2123 | 7 | String element = st.nextToken(); |
2124 | ||
2125 | 7 | out.append( capitalizeFirstLetter( element ) ); |
2126 | 7 | } |
2127 | ||
2128 | 3 | return out.toString(); |
2129 | } | |
2130 | ||
2131 | /** | |
2132 | * Convert the first character of the given String to uppercase. | |
2133 | * This method will <i>not</i> trim of spaces! | |
2134 | * <p/> | |
2135 | * <p> | |
2136 | * <b>Attention:</b> this method will currently throw a | |
2137 | * <code>IndexOutOfBoundsException</code> for empty strings! | |
2138 | * </p> | |
2139 | * | |
2140 | * @param data the String to get capitalized | |
2141 | * @return data string with the first character transformed to uppercase | |
2142 | * @throws NullPointerException if data is <code>null</code> | |
2143 | */ | |
2144 | public @Nonnull static String capitalizeFirstLetter( @Nonnull String data ) | |
2145 | { | |
2146 | 33 | char firstLetter = Character.toTitleCase( data.substring( 0, 1 ).charAt( 0 ) ); |
2147 | ||
2148 | 32 | String restLetters = data.substring( 1 ); |
2149 | ||
2150 | 32 | return firstLetter + restLetters; |
2151 | } | |
2152 | ||
2153 | /** | |
2154 | * Convert the first character of the given String to lowercase. | |
2155 | * This method will <i>not</i> trim of spaces! | |
2156 | * <p/> | |
2157 | * <p> | |
2158 | * <b>Attention:</b> this method will currently throw a | |
2159 | * <code>IndexOutOfBoundsException</code> for empty strings! | |
2160 | * </p> | |
2161 | * | |
2162 | * @param data the String to get it's first character lower-cased. | |
2163 | * @return data string with the first character transformed to lowercase | |
2164 | * @throws NullPointerException if data is <code>null</code> | |
2165 | */ | |
2166 | public @Nonnull static String lowercaseFirstLetter( @Nonnull String data ) | |
2167 | { | |
2168 | 2 | char firstLetter = Character.toLowerCase( data.substring( 0, 1 ).charAt( 0 ) ); |
2169 | ||
2170 | 1 | String restLetters = data.substring( 1 ); |
2171 | ||
2172 | 1 | return firstLetter + restLetters; |
2173 | } | |
2174 | ||
2175 | /** | |
2176 | * Take the input string and un-camel-case it. | |
2177 | * <p/> | |
2178 | * 'ThisIsIt' will become 'this-is-it'. | |
2179 | * | |
2180 | * @param view | |
2181 | * @return deHumped String | |
2182 | */ | |
2183 | public @Nonnull static String addAndDeHump( @Nonnull String view ) | |
2184 | { | |
2185 | 4 | StringBuilder sb = new StringBuilder(); |
2186 | ||
2187 | 24 | for ( int i = 0; i < view.length(); i++ ) |
2188 | { | |
2189 | 20 | if ( ( i != 0 ) && Character.isUpperCase( view.charAt( i ) ) ) |
2190 | { | |
2191 | 9 | sb.append( '-' ); |
2192 | } | |
2193 | ||
2194 | 20 | sb.append( view.charAt( i ) ); |
2195 | } | |
2196 | ||
2197 | 3 | return sb.toString().trim().toLowerCase( Locale.ENGLISH ); |
2198 | } | |
2199 | ||
2200 | /** | |
2201 | * <p>Quote and escape a String with the given character, handling <code>null</code>.</p> | |
2202 | * <p/> | |
2203 | * <pre> | |
2204 | * StringUtils.quoteAndEscape(null, *) = null | |
2205 | * StringUtils.quoteAndEscape("", *) = "" | |
2206 | * StringUtils.quoteAndEscape("abc", '"') = abc | |
2207 | * StringUtils.quoteAndEscape("a\"bc", '"') = "a\"bc" | |
2208 | * StringUtils.quoteAndEscape("a\"bc", '\'') = 'a\"bc' | |
2209 | * </pre> | |
2210 | * | |
2211 | * @param source | |
2212 | * @param quoteChar | |
2213 | * @return the String quoted and escaped | |
2214 | * @see #quoteAndEscape(String, char, char[], char[], char, boolean) | |
2215 | * @see #quoteAndEscape(String, char, char[], char[], char, boolean) | |
2216 | * | |
2217 | */ | |
2218 | public static String quoteAndEscape( @Nullable String source, char quoteChar ) | |
2219 | { | |
2220 | 6 | return quoteAndEscape( source, quoteChar, new char[]{ quoteChar }, new char[]{ ' ' }, '\\', false ); |
2221 | } | |
2222 | ||
2223 | /** | |
2224 | * <p>Quote and escape a String with the given character, handling <code>null</code>.</p> | |
2225 | * | |
2226 | * @param source | |
2227 | * @param quoteChar | |
2228 | * @param quotingTriggers | |
2229 | * @return the String quoted and escaped | |
2230 | * @see #quoteAndEscape(String, char, char[], char[], char, boolean) | |
2231 | * | |
2232 | */ | |
2233 | public static String quoteAndEscape( @Nullable String source, char quoteChar, @Nonnull char[] quotingTriggers ) | |
2234 | { | |
2235 | 31 | return quoteAndEscape( source, quoteChar, new char[]{ quoteChar }, quotingTriggers, '\\', false ); |
2236 | } | |
2237 | ||
2238 | /** | |
2239 | * @param source | |
2240 | * @param quoteChar | |
2241 | * @param escapedChars | |
2242 | * @param escapeChar | |
2243 | * @param force | |
2244 | * @return the String quoted and escaped | |
2245 | * @see #quoteAndEscape(String, char, char[], char[], char, boolean) | |
2246 | * | |
2247 | */ | |
2248 | public static String quoteAndEscape( @Nullable String source, char quoteChar, @Nonnull final char[] escapedChars, char escapeChar, | |
2249 | boolean force ) | |
2250 | { | |
2251 | 14 | return quoteAndEscape( source, quoteChar, escapedChars, new char[]{ ' ' }, escapeChar, force ); |
2252 | } | |
2253 | ||
2254 | /** | |
2255 | * @param source | |
2256 | * @param quoteChar | |
2257 | * @param escapedChars | |
2258 | * @param quotingTriggers | |
2259 | * @param escapeChar | |
2260 | * @param force | |
2261 | * @return the String quoted and escaped | |
2262 | * | |
2263 | */ | |
2264 | public static String quoteAndEscape( @Nullable String source, char quoteChar, @Nonnull final char[] escapedChars, | |
2265 | @Nonnull final char[] quotingTriggers, char escapeChar, boolean force ) | |
2266 | { | |
2267 | 102 | if ( source == null ) |
2268 | { | |
2269 | 6 | return null; |
2270 | } | |
2271 | ||
2272 | 96 | if ( !force && source.startsWith( Character.toString( quoteChar ) ) && source.endsWith( |
2273 | Character.toString( quoteChar ) ) ) | |
2274 | { | |
2275 | 2 | return source; |
2276 | } | |
2277 | ||
2278 | 94 | String escaped = escape( source, escapedChars, escapeChar ); |
2279 | ||
2280 | 94 | boolean quote = false; |
2281 | 94 | if ( force ) |
2282 | { | |
2283 | 12 | quote = true; |
2284 | } | |
2285 | 82 | else if ( !escaped.equals( source ) ) |
2286 | { | |
2287 | 7 | quote = true; |
2288 | } | |
2289 | else | |
2290 | { | |
2291 | 753 | for ( char quotingTrigger : quotingTriggers ) |
2292 | { | |
2293 | 705 | if ( escaped.indexOf( quotingTrigger ) > -1 ) |
2294 | { | |
2295 | 27 | quote = true; |
2296 | 27 | break; |
2297 | } | |
2298 | } | |
2299 | } | |
2300 | ||
2301 | 94 | if ( quote ) |
2302 | { | |
2303 | 46 | return quoteChar + escaped + quoteChar; |
2304 | } | |
2305 | ||
2306 | 48 | return escaped; |
2307 | } | |
2308 | ||
2309 | /** | |
2310 | * @param source | |
2311 | * @param escapedChars | |
2312 | * @param escapeChar | |
2313 | * @return the String escaped | |
2314 | * | |
2315 | */ | |
2316 | public static String escape( @Nullable String source, @Nonnull final char[] escapedChars, char escapeChar ) | |
2317 | { | |
2318 | 99 | if ( source == null ) |
2319 | { | |
2320 | 1 | return null; |
2321 | } | |
2322 | ||
2323 | 98 | char[] eqc = new char[escapedChars.length]; |
2324 | 98 | System.arraycopy( escapedChars, 0, eqc, 0, escapedChars.length ); |
2325 | 98 | Arrays.sort( eqc ); |
2326 | ||
2327 | 98 | StringBuilder buffer = new StringBuilder( source.length() ); |
2328 | ||
2329 | 591 | for ( int i = 0; i < source.length(); i++ ) |
2330 | { | |
2331 | 493 | final char c = source.charAt( i ); |
2332 | 493 | int result = Arrays.binarySearch( eqc, c ); |
2333 | ||
2334 | 493 | if ( result > -1 ) |
2335 | { | |
2336 | 13 | buffer.append( escapeChar ); |
2337 | } | |
2338 | 493 | buffer.append( c ); |
2339 | } | |
2340 | ||
2341 | 98 | return buffer.toString(); |
2342 | } | |
2343 | ||
2344 | /** | |
2345 | * Remove all duplicate whitespace characters and line terminators are replaced with a single | |
2346 | * space. | |
2347 | * | |
2348 | * @param s a not null String | |
2349 | * @return a string with unique whitespace. | |
2350 | * | |
2351 | */ | |
2352 | public @Nonnull static String removeDuplicateWhitespace( @Nonnull String s ) | |
2353 | { | |
2354 | 5 | StringBuilder result = new StringBuilder(); |
2355 | 5 | int length = s.length(); |
2356 | 4 | boolean isPreviousWhiteSpace = false; |
2357 | 42 | for ( int i = 0; i < length; i++ ) |
2358 | { | |
2359 | 38 | char c = s.charAt( i ); |
2360 | 38 | boolean thisCharWhiteSpace = Character.isWhitespace( c ); |
2361 | 38 | if ( !( isPreviousWhiteSpace && thisCharWhiteSpace ) ) |
2362 | { | |
2363 | 35 | result.append( c ); |
2364 | } | |
2365 | 38 | isPreviousWhiteSpace = thisCharWhiteSpace; |
2366 | } | |
2367 | 4 | return result.toString(); |
2368 | } | |
2369 | ||
2370 | /** | |
2371 | * Parses the given String and replaces all occurrences of | |
2372 | * '\n', '\r' and '\r\n' with the system line separator. | |
2373 | * | |
2374 | * @param s a not null String | |
2375 | * @return a String that contains only System line separators. | |
2376 | * @see #unifyLineSeparators(String, String) | |
2377 | * | |
2378 | */ | |
2379 | public static String unifyLineSeparators( @Nullable String s ) | |
2380 | { | |
2381 | 6 | return unifyLineSeparators( s, System.getProperty( "line.separator" ) ); |
2382 | } | |
2383 | ||
2384 | /** | |
2385 | * Parses the given String and replaces all occurrences of | |
2386 | * '\n', '\r' and '\r\n' with the system line separator. | |
2387 | * | |
2388 | * @param s a not null String | |
2389 | * @param ls the wanted line separator ("\n" on UNIX), if null using the System line separator. | |
2390 | * @return a String that contains only System line separators. | |
2391 | * @throws IllegalArgumentException if ls is not '\n', '\r' and '\r\n' characters. | |
2392 | * | |
2393 | */ | |
2394 | public static String unifyLineSeparators( @Nullable String s, @Nullable String ls ) | |
2395 | { | |
2396 | 10 | if ( s == null ) |
2397 | { | |
2398 | 2 | return null; |
2399 | } | |
2400 | ||
2401 | 8 | if ( ls == null ) |
2402 | { | |
2403 | 1 | ls = System.getProperty( "line.separator" ); |
2404 | } | |
2405 | ||
2406 | 8 | if ( !( ls.equals( "\n" ) || ls.equals( "\r" ) || ls.equals( "\r\n" ) ) ) |
2407 | { | |
2408 | 0 | throw new IllegalArgumentException( "Requested line separator is invalid." ); |
2409 | } | |
2410 | ||
2411 | 8 | int length = s.length(); |
2412 | ||
2413 | 8 | StringBuilder buffer = new StringBuilder( length ); |
2414 | 214 | for ( int i = 0; i < length; i++ ) |
2415 | { | |
2416 | 206 | if ( s.charAt( i ) == '\r' ) |
2417 | { | |
2418 | 2 | if ( ( i + 1 ) < length && s.charAt( i + 1 ) == '\n' ) |
2419 | { | |
2420 | 2 | i++; |
2421 | } | |
2422 | ||
2423 | 2 | buffer.append( ls ); |
2424 | } | |
2425 | 204 | else if ( s.charAt( i ) == '\n' ) |
2426 | { | |
2427 | 12 | buffer.append( ls ); |
2428 | } | |
2429 | else | |
2430 | { | |
2431 | 192 | buffer.append( s.charAt( i ) ); |
2432 | } | |
2433 | } | |
2434 | ||
2435 | 8 | return buffer.toString(); |
2436 | } | |
2437 | ||
2438 | /** | |
2439 | * <p>Checks if String contains a search character, handling <code>null</code>. | |
2440 | * This method uses {@link String#indexOf(int)}.</p> | |
2441 | * <p/> | |
2442 | * <p>A <code>null</code> or empty ("") String will return <code>false</code>.</p> | |
2443 | * <p/> | |
2444 | * <pre> | |
2445 | * StringUtils.contains(null, *) = false | |
2446 | * StringUtils.contains("", *) = false | |
2447 | * StringUtils.contains("abc", 'a') = true | |
2448 | * StringUtils.contains("abc", 'z') = false | |
2449 | * </pre> | |
2450 | * | |
2451 | * @param str the String to check, may be null | |
2452 | * @param searchChar the character to find | |
2453 | * @return true if the String contains the search character, | |
2454 | * false if not or <code>null</code> string input | |
2455 | * | |
2456 | */ | |
2457 | @SuppressWarnings( "ConstantConditions" ) | |
2458 | public static boolean contains( @Nullable String str, char searchChar ) | |
2459 | { | |
2460 | 1 | return !isEmpty( str ) && str.indexOf( searchChar ) >= 0; |
2461 | } | |
2462 | ||
2463 | /** | |
2464 | * <p>Checks if String contains a search String, handling <code>null</code>. | |
2465 | * This method uses {@link String#indexOf(int)}.</p> | |
2466 | * <p/> | |
2467 | * <p>A <code>null</code> String will return <code>false</code>.</p> | |
2468 | * <p/> | |
2469 | * <pre> | |
2470 | * StringUtils.contains(null, *) = false | |
2471 | * StringUtils.contains(*, null) = false | |
2472 | * StringUtils.contains("", "") = true | |
2473 | * StringUtils.contains("abc", "") = true | |
2474 | * StringUtils.contains("abc", "a") = true | |
2475 | * StringUtils.contains("abc", "z") = false | |
2476 | * </pre> | |
2477 | * | |
2478 | * @param str the String to check, may be null | |
2479 | * @param searchStr the String to find, may be null | |
2480 | * @return true if the String contains the search String, | |
2481 | * false if not or <code>null</code> string input | |
2482 | * | |
2483 | */ | |
2484 | public static boolean contains( @Nullable String str, @Nullable String searchStr ) | |
2485 | { | |
2486 | 10 | return !( str == null || searchStr == null ) && str.contains( searchStr ); |
2487 | } | |
2488 | } |