001/*
002* Licensed to the Apache Software Foundation (ASF) under one or more
003* contributor license agreements.  See the NOTICE file distributed with
004* this work for additional information regarding copyright ownership.
005* The ASF licenses this file to You under the Apache License, Version 2.0
006* (the "License"); you may not use this file except in compliance with
007* the License.  You may obtain a copy of the License at
008*
009*      http://www.apache.org/licenses/LICENSE-2.0
010*
011* Unless required by applicable law or agreed to in writing, software
012* distributed under the License is distributed on an "AS IS" BASIS,
013* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014* See the License for the specific language governing permissions and
015* limitations under the License.
016*/
017
018package co.aikar.commands.apachecommonslang;
019
020import java.lang.reflect.Array;
021import java.util.Iterator;
022
023/**
024 * Select methods copied from Apache Commons to avoid importing entire lib
025 * No changes to logic
026 */
027public class ApacheCommonsLangUtil {
028
029    /**
030     * The empty String {@code ""}.
031     * @since 2.0
032     */
033    public static final String EMPTY = "";
034    /**
035     * <p>Shallow clones an array returning a typecast result and handling
036     * {@code null}.
037     *
038     * <p>The objects in the array are not cloned, thus there is no special
039     * handling for multi-dimensional arrays.
040     *
041     * <p>This method returns {@code null} for a {@code null} input array.
042     *
043     * @param <T> the component type of the array
044     * @param array  the array to shallow clone, may be {@code null}
045     * @return the cloned array, {@code null} if {@code null} input
046     */
047    public static <T> T[] clone(final T[] array) {
048        if (array == null) {
049            return null;
050        }
051        return array.clone();
052    }
053
054    /**
055     * <p>Adds all the elements of the given arrays into a new array.
056     * <p>The new array contains all of the element of {@code array1} followed
057     * by all of the elements {@code array2}. When an array is returned, it is always
058     * a new array.
059     *
060     * <pre>
061     * ArrayUtils.addAll(null, null)     = null
062     * ArrayUtils.addAll(array1, null)   = cloned copy of array1
063     * ArrayUtils.addAll(null, array2)   = cloned copy of array2
064     * ArrayUtils.addAll([], [])         = []
065     * ArrayUtils.addAll([null], [null]) = [null, null]
066     * ArrayUtils.addAll(["a", "b", "c"], ["1", "2", "3"]) = ["a", "b", "c", "1", "2", "3"]
067     * </pre>
068     *
069     * @param <T> the component type of the array
070     * @param array1  the first array whose elements are added to the new array, may be {@code null}
071     * @param array2  the second array whose elements are added to the new array, may be {@code null}
072     * @return The new array, {@code null} if both arrays are {@code null}.
073     *      The type of the new array is the type of the first array,
074     *      unless the first array is null, in which case the type is the same as the second array.
075     * @since 2.1
076     * @throws IllegalArgumentException if the array types are incompatible
077     */
078    public static <T> T[] addAll(final T[] array1, final T... array2) {
079        if (array1 == null) {
080            return clone(array2);
081        } else if (array2 == null) {
082            return clone(array1);
083        }
084        final Class<?> type1 = array1.getClass().getComponentType();
085        @SuppressWarnings("unchecked") // OK, because array is of type T
086        final T[] joinedArray = (T[]) Array.newInstance(type1, array1.length + array2.length);
087        System.arraycopy(array1, 0, joinedArray, 0, array1.length);
088        try {
089            System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
090        } catch (final ArrayStoreException ase) {
091            // Check if problem was due to incompatible types
092            /*
093             * We do this here, rather than before the copy because:
094             * - it would be a wasted check most of the time
095             * - safer, in case check turns out to be too strict
096             */
097            final Class<?> type2 = array2.getClass().getComponentType();
098            if (!type1.isAssignableFrom(type2)) {
099                throw new IllegalArgumentException("Cannot store " + type2.getName() + " in an array of "
100                        + type1.getName(), ase);
101            }
102            throw ase; // No, so rethrow original
103        }
104        return joinedArray;
105    }
106
107    //-----------------------------------------------------------------------
108    /**
109     * <p>Converts all the whitespace separated words in a String into capitalized words,
110     * that is each word is made up of a titlecase character and then a series of
111     * lowercase characters.  </p>
112     *
113     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
114     * A <code>null</code> input String returns <code>null</code>.
115     * Capitalization uses the Unicode title case, normally equivalent to
116     * upper case.</p>
117     *
118     * <pre>
119     * WordUtils.capitalizeFully(null)        = null
120     * WordUtils.capitalizeFully("")          = ""
121     * WordUtils.capitalizeFully("i am FINE") = "I Am Fine"
122     * </pre>
123     *
124     * @param str  the String to capitalize, may be null
125     * @return capitalized String, <code>null</code> if null String input
126     */
127    public static String capitalizeFully(final String str) {
128        return capitalizeFully(str, null);
129    }
130
131    /**
132     * <p>Converts all the delimiter separated words in a String into capitalized words,
133     * that is each word is made up of a titlecase character and then a series of
134     * lowercase characters. </p>
135     *
136     * <p>The delimiters represent a set of characters understood to separate words.
137     * The first string character and the first non-delimiter character after a
138     * delimiter will be capitalized. </p>
139     *
140     * <p>A <code>null</code> input String returns <code>null</code>.
141     * Capitalization uses the Unicode title case, normally equivalent to
142     * upper case.</p>
143     *
144     * <pre>
145     * WordUtils.capitalizeFully(null, *)            = null
146     * WordUtils.capitalizeFully("", *)              = ""
147     * WordUtils.capitalizeFully(*, null)            = *
148     * WordUtils.capitalizeFully(*, new char[0])     = *
149     * WordUtils.capitalizeFully("i aM.fine", {'.'}) = "I am.Fine"
150     * </pre>
151     *
152     * @param str  the String to capitalize, may be null
153     * @param delimiters  set of characters to determine capitalization, null means whitespace
154     * @return capitalized String, <code>null</code> if null String input
155     * @since 2.1
156     */
157    public static String capitalizeFully(String str, final char... delimiters) {
158        final int delimLen = delimiters == null ? -1 : delimiters.length;
159        if (str == null || str.isEmpty() || delimLen == 0) {
160            return str;
161        }
162        str = str.toLowerCase();
163        return capitalize(str, delimiters);
164    }
165
166    // Capitalizing
167    //-----------------------------------------------------------------------
168    /**
169     * <p>Capitalizes all the whitespace separated words in a String.
170     * Only the first character of each word is changed. To convert the
171     * rest of each word to lowercase at the same time,
172     * use {@link #capitalizeFully(String)}.</p>
173     *
174     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
175     * A <code>null</code> input String returns <code>null</code>.
176     * Capitalization uses the Unicode title case, normally equivalent to
177     * upper case.</p>
178     *
179     * <pre>
180     * WordUtils.capitalize(null)        = null
181     * WordUtils.capitalize("")          = ""
182     * WordUtils.capitalize("i am FINE") = "I Am FINE"
183     * </pre>
184     *
185     * @param str  the String to capitalize, may be null
186     * @return capitalized String, <code>null</code> if null String input
187     * @see #capitalizeFully(String)
188     */
189    public static String capitalize(final String str) {
190        return capitalize(str, null);
191    }
192
193    /**
194     * <p>Capitalizes all the delimiter separated words in a String.
195     * Only the first character of each word is changed. To convert the
196     * rest of each word to lowercase at the same time,
197     * use {@link #capitalizeFully(String, char[])}.</p>
198     *
199     * <p>The delimiters represent a set of characters understood to separate words.
200     * The first string character and the first non-delimiter character after a
201     * delimiter will be capitalized. </p>
202     *
203     * <p>A <code>null</code> input String returns <code>null</code>.
204     * Capitalization uses the Unicode title case, normally equivalent to
205     * upper case.</p>
206     *
207     * <pre>
208     * WordUtils.capitalize(null, *)            = null
209     * WordUtils.capitalize("", *)              = ""
210     * WordUtils.capitalize(*, new char[0])     = *
211     * WordUtils.capitalize("i am fine", null)  = "I Am Fine"
212     * WordUtils.capitalize("i aM.fine", {'.'}) = "I aM.Fine"
213     * </pre>
214     *
215     * @param str  the String to capitalize, may be null
216     * @param delimiters  set of characters to determine capitalization, null means whitespace
217     * @return capitalized String, <code>null</code> if null String input
218     * @see #capitalizeFully(String)
219     * @since 2.1
220     */
221    public static String capitalize(final String str, final char... delimiters) {
222        final int delimLen = delimiters == null ? -1 : delimiters.length;
223        if (str == null || str.isEmpty() || delimLen == 0) {
224            return str;
225        }
226        final char[] buffer = str.toCharArray();
227        boolean capitalizeNext = true;
228        for (int i = 0; i < buffer.length; i++) {
229            final char ch = buffer[i];
230            if (isDelimiter(ch, delimiters)) {
231                capitalizeNext = true;
232            } else if (capitalizeNext) {
233                buffer[i] = Character.toTitleCase(ch);
234                capitalizeNext = false;
235            }
236        }
237        return new String(buffer);
238    }
239    //-----------------------------------------------------------------------
240    /**
241     * Is the character a delimiter.
242     *
243     * @param ch  the character to check
244     * @param delimiters  the delimiters
245     * @return true if it is a delimiter
246     */
247    public static boolean isDelimiter(final char ch, final char[] delimiters) {
248        if (delimiters == null) {
249            return Character.isWhitespace(ch);
250        }
251        for (final char delimiter : delimiters) {
252            if (ch == delimiter) {
253                return true;
254            }
255        }
256        return false;
257    }
258
259    // Joining
260    //-----------------------------------------------------------------------
261    /**
262     * <p>Joins the elements of the provided array into a single String
263     * containing the provided list of elements.</p>
264     *
265     * <p>No separator is added to the joined String.
266     * Null objects or empty strings within the array are represented by
267     * empty strings.</p>
268     *
269     * <pre>
270     * StringUtils.join(null)            = null
271     * StringUtils.join([])              = ""
272     * StringUtils.join([null])          = ""
273     * StringUtils.join(["a", "b", "c"]) = "abc"
274     * StringUtils.join([null, "", "a"]) = "a"
275     * </pre>
276     *
277     * @param <T> the specific type of values to join together
278     * @param elements  the values to join together, may be null
279     * @return the joined String, {@code null} if null array input
280     * @since 2.0
281     * @since 3.0 Changed signature to use varargs
282     */
283    @SafeVarargs
284    public static <T> String join(final T... elements) {
285        return join(elements, null);
286    }
287
288    /**
289     * <p>Joins the elements of the provided array into a single String
290     * containing the provided list of elements.</p>
291     *
292     * <p>No delimiter is added before or after the list.
293     * Null objects or empty strings within the array are represented by
294     * empty strings.</p>
295     *
296     * <pre>
297     * StringUtils.join(null, *)               = null
298     * StringUtils.join([], *)                 = ""
299     * StringUtils.join([null], *)             = ""
300     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
301     * StringUtils.join(["a", "b", "c"], null) = "abc"
302     * StringUtils.join([null, "", "a"], ';')  = ";;a"
303     * </pre>
304     *
305     * @param array  the array of values to join together, may be null
306     * @param separator  the separator character to use
307     * @return the joined String, {@code null} if null array input
308     * @since 2.0
309     */
310    public static String join(final Object[] array, final char separator) {
311        if (array == null) {
312            return null;
313        }
314        return join(array, separator, 0, array.length);
315    }
316
317    /**
318     * <p>
319     * Joins the elements of the provided array into a single String containing the provided list of elements.
320     * </p>
321     *
322     * <p>
323     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
324     * by empty strings.
325     * </p>
326     *
327     * <pre>
328     * StringUtils.join(null, *)               = null
329     * StringUtils.join([], *)                 = ""
330     * StringUtils.join([null], *)             = ""
331     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
332     * StringUtils.join([1, 2, 3], null) = "123"
333     * </pre>
334     *
335     * @param array
336     *            the array of values to join together, may be null
337     * @param separator
338     *            the separator character to use
339     * @return the joined String, {@code null} if null array input
340     * @since 3.2
341     */
342    public static String join(final long[] array, final char separator) {
343        if (array == null) {
344            return null;
345        }
346        return join(array, separator, 0, array.length);
347    }
348
349    /**
350     * <p>
351     * Joins the elements of the provided array into a single String containing the provided list of elements.
352     * </p>
353     *
354     * <p>
355     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
356     * by empty strings.
357     * </p>
358     *
359     * <pre>
360     * StringUtils.join(null, *)               = null
361     * StringUtils.join([], *)                 = ""
362     * StringUtils.join([null], *)             = ""
363     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
364     * StringUtils.join([1, 2, 3], null) = "123"
365     * </pre>
366     *
367     * @param array
368     *            the array of values to join together, may be null
369     * @param separator
370     *            the separator character to use
371     * @return the joined String, {@code null} if null array input
372     * @since 3.2
373     */
374    public static String join(final int[] array, final char separator) {
375        if (array == null) {
376            return null;
377        }
378        return join(array, separator, 0, array.length);
379    }
380
381    /**
382     * <p>
383     * Joins the elements of the provided array into a single String containing the provided list of elements.
384     * </p>
385     *
386     * <p>
387     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
388     * by empty strings.
389     * </p>
390     *
391     * <pre>
392     * StringUtils.join(null, *)               = null
393     * StringUtils.join([], *)                 = ""
394     * StringUtils.join([null], *)             = ""
395     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
396     * StringUtils.join([1, 2, 3], null) = "123"
397     * </pre>
398     *
399     * @param array
400     *            the array of values to join together, may be null
401     * @param separator
402     *            the separator character to use
403     * @return the joined String, {@code null} if null array input
404     * @since 3.2
405     */
406    public static String join(final short[] array, final char separator) {
407        if (array == null) {
408            return null;
409        }
410        return join(array, separator, 0, array.length);
411    }
412
413    /**
414     * <p>
415     * Joins the elements of the provided array into a single String containing the provided list of elements.
416     * </p>
417     *
418     * <p>
419     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
420     * by empty strings.
421     * </p>
422     *
423     * <pre>
424     * StringUtils.join(null, *)               = null
425     * StringUtils.join([], *)                 = ""
426     * StringUtils.join([null], *)             = ""
427     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
428     * StringUtils.join([1, 2, 3], null) = "123"
429     * </pre>
430     *
431     * @param array
432     *            the array of values to join together, may be null
433     * @param separator
434     *            the separator character to use
435     * @return the joined String, {@code null} if null array input
436     * @since 3.2
437     */
438    public static String join(final byte[] array, final char separator) {
439        if (array == null) {
440            return null;
441        }
442        return join(array, separator, 0, array.length);
443    }
444
445    /**
446     * <p>
447     * Joins the elements of the provided array into a single String containing the provided list of elements.
448     * </p>
449     *
450     * <p>
451     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
452     * by empty strings.
453     * </p>
454     *
455     * <pre>
456     * StringUtils.join(null, *)               = null
457     * StringUtils.join([], *)                 = ""
458     * StringUtils.join([null], *)             = ""
459     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
460     * StringUtils.join([1, 2, 3], null) = "123"
461     * </pre>
462     *
463     * @param array
464     *            the array of values to join together, may be null
465     * @param separator
466     *            the separator character to use
467     * @return the joined String, {@code null} if null array input
468     * @since 3.2
469     */
470    public static String join(final char[] array, final char separator) {
471        if (array == null) {
472            return null;
473        }
474        return join(array, separator, 0, array.length);
475    }
476
477    /**
478     * <p>
479     * Joins the elements of the provided array into a single String containing the provided list of elements.
480     * </p>
481     *
482     * <p>
483     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
484     * by empty strings.
485     * </p>
486     *
487     * <pre>
488     * StringUtils.join(null, *)               = null
489     * StringUtils.join([], *)                 = ""
490     * StringUtils.join([null], *)             = ""
491     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
492     * StringUtils.join([1, 2, 3], null) = "123"
493     * </pre>
494     *
495     * @param array
496     *            the array of values to join together, may be null
497     * @param separator
498     *            the separator character to use
499     * @return the joined String, {@code null} if null array input
500     * @since 3.2
501     */
502    public static String join(final float[] array, final char separator) {
503        if (array == null) {
504            return null;
505        }
506        return join(array, separator, 0, array.length);
507    }
508
509    /**
510     * <p>
511     * Joins the elements of the provided array into a single String containing the provided list of elements.
512     * </p>
513     *
514     * <p>
515     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
516     * by empty strings.
517     * </p>
518     *
519     * <pre>
520     * StringUtils.join(null, *)               = null
521     * StringUtils.join([], *)                 = ""
522     * StringUtils.join([null], *)             = ""
523     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
524     * StringUtils.join([1, 2, 3], null) = "123"
525     * </pre>
526     *
527     * @param array
528     *            the array of values to join together, may be null
529     * @param separator
530     *            the separator character to use
531     * @return the joined String, {@code null} if null array input
532     * @since 3.2
533     */
534    public static String join(final double[] array, final char separator) {
535        if (array == null) {
536            return null;
537        }
538        return join(array, separator, 0, array.length);
539    }
540
541
542    /**
543     * <p>Joins the elements of the provided array into a single String
544     * containing the provided list of elements.</p>
545     *
546     * <p>No delimiter is added before or after the list.
547     * Null objects or empty strings within the array are represented by
548     * empty strings.</p>
549     *
550     * <pre>
551     * StringUtils.join(null, *)               = null
552     * StringUtils.join([], *)                 = ""
553     * StringUtils.join([null], *)             = ""
554     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
555     * StringUtils.join(["a", "b", "c"], null) = "abc"
556     * StringUtils.join([null, "", "a"], ';')  = ";;a"
557     * </pre>
558     *
559     * @param array  the array of values to join together, may be null
560     * @param separator  the separator character to use
561     * @param startIndex the first index to start joining from.  It is
562     * an error to pass in an end index past the end of the array
563     * @param endIndex the index to stop joining from (exclusive). It is
564     * an error to pass in an end index past the end of the array
565     * @return the joined String, {@code null} if null array input
566     * @since 2.0
567     */
568    public static String join(final Object[] array, final char separator, final int startIndex, final int endIndex) {
569        if (array == null) {
570            return null;
571        }
572        final int noOfItems = endIndex - startIndex;
573        if (noOfItems <= 0) {
574            return EMPTY;
575        }
576        final StringBuilder buf = new StringBuilder(noOfItems * 16);
577        for (int i = startIndex; i < endIndex; i++) {
578            if (i > startIndex) {
579                buf.append(separator);
580            }
581            if (array[i] != null) {
582                buf.append(array[i]);
583            }
584        }
585        return buf.toString();
586    }
587
588    /**
589     * <p>
590     * Joins the elements of the provided array into a single String containing the provided list of elements.
591     * </p>
592     *
593     * <p>
594     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
595     * by empty strings.
596     * </p>
597     *
598     * <pre>
599     * StringUtils.join(null, *)               = null
600     * StringUtils.join([], *)                 = ""
601     * StringUtils.join([null], *)             = ""
602     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
603     * StringUtils.join([1, 2, 3], null) = "123"
604     * </pre>
605     *
606     * @param array
607     *            the array of values to join together, may be null
608     * @param separator
609     *            the separator character to use
610     * @param startIndex
611     *            the first index to start joining from. It is an error to pass in an end index past the end of the
612     *            array
613     * @param endIndex
614     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
615     *            the array
616     * @return the joined String, {@code null} if null array input
617     * @since 3.2
618     */
619    public static String join(final long[] array, final char separator, final int startIndex, final int endIndex) {
620        if (array == null) {
621            return null;
622        }
623        final int noOfItems = endIndex - startIndex;
624        if (noOfItems <= 0) {
625            return EMPTY;
626        }
627        final StringBuilder buf = new StringBuilder(noOfItems * 16);
628        for (int i = startIndex; i < endIndex; i++) {
629            if (i > startIndex) {
630                buf.append(separator);
631            }
632            buf.append(array[i]);
633        }
634        return buf.toString();
635    }
636
637    /**
638     * <p>
639     * Joins the elements of the provided array into a single String containing the provided list of elements.
640     * </p>
641     *
642     * <p>
643     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
644     * by empty strings.
645     * </p>
646     *
647     * <pre>
648     * StringUtils.join(null, *)               = null
649     * StringUtils.join([], *)                 = ""
650     * StringUtils.join([null], *)             = ""
651     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
652     * StringUtils.join([1, 2, 3], null) = "123"
653     * </pre>
654     *
655     * @param array
656     *            the array of values to join together, may be null
657     * @param separator
658     *            the separator character to use
659     * @param startIndex
660     *            the first index to start joining from. It is an error to pass in an end index past the end of the
661     *            array
662     * @param endIndex
663     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
664     *            the array
665     * @return the joined String, {@code null} if null array input
666     * @since 3.2
667     */
668    public static String join(final int[] array, final char separator, final int startIndex, final int endIndex) {
669        if (array == null) {
670            return null;
671        }
672        final int noOfItems = endIndex - startIndex;
673        if (noOfItems <= 0) {
674            return EMPTY;
675        }
676        final StringBuilder buf = new StringBuilder(noOfItems * 16);
677        for (int i = startIndex; i < endIndex; i++) {
678            if (i > startIndex) {
679                buf.append(separator);
680            }
681            buf.append(array[i]);
682        }
683        return buf.toString();
684    }
685
686    /**
687     * <p>
688     * Joins the elements of the provided array into a single String containing the provided list of elements.
689     * </p>
690     *
691     * <p>
692     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
693     * by empty strings.
694     * </p>
695     *
696     * <pre>
697     * StringUtils.join(null, *)               = null
698     * StringUtils.join([], *)                 = ""
699     * StringUtils.join([null], *)             = ""
700     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
701     * StringUtils.join([1, 2, 3], null) = "123"
702     * </pre>
703     *
704     * @param array
705     *            the array of values to join together, may be null
706     * @param separator
707     *            the separator character to use
708     * @param startIndex
709     *            the first index to start joining from. It is an error to pass in an end index past the end of the
710     *            array
711     * @param endIndex
712     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
713     *            the array
714     * @return the joined String, {@code null} if null array input
715     * @since 3.2
716     */
717    public static String join(final byte[] array, final char separator, final int startIndex, final int endIndex) {
718        if (array == null) {
719            return null;
720        }
721        final int noOfItems = endIndex - startIndex;
722        if (noOfItems <= 0) {
723            return EMPTY;
724        }
725        final StringBuilder buf = new StringBuilder(noOfItems * 16);
726        for (int i = startIndex; i < endIndex; i++) {
727            if (i > startIndex) {
728                buf.append(separator);
729            }
730            buf.append(array[i]);
731        }
732        return buf.toString();
733    }
734
735    /**
736     * <p>
737     * Joins the elements of the provided array into a single String containing the provided list of elements.
738     * </p>
739     *
740     * <p>
741     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
742     * by empty strings.
743     * </p>
744     *
745     * <pre>
746     * StringUtils.join(null, *)               = null
747     * StringUtils.join([], *)                 = ""
748     * StringUtils.join([null], *)             = ""
749     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
750     * StringUtils.join([1, 2, 3], null) = "123"
751     * </pre>
752     *
753     * @param array
754     *            the array of values to join together, may be null
755     * @param separator
756     *            the separator character to use
757     * @param startIndex
758     *            the first index to start joining from. It is an error to pass in an end index past the end of the
759     *            array
760     * @param endIndex
761     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
762     *            the array
763     * @return the joined String, {@code null} if null array input
764     * @since 3.2
765     */
766    public static String join(final short[] array, final char separator, final int startIndex, final int endIndex) {
767        if (array == null) {
768            return null;
769        }
770        final int noOfItems = endIndex - startIndex;
771        if (noOfItems <= 0) {
772            return EMPTY;
773        }
774        final StringBuilder buf = new StringBuilder(noOfItems * 16);
775        for (int i = startIndex; i < endIndex; i++) {
776            if (i > startIndex) {
777                buf.append(separator);
778            }
779            buf.append(array[i]);
780        }
781        return buf.toString();
782    }
783
784    /**
785     * <p>
786     * Joins the elements of the provided array into a single String containing the provided list of elements.
787     * </p>
788     *
789     * <p>
790     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
791     * by empty strings.
792     * </p>
793     *
794     * <pre>
795     * StringUtils.join(null, *)               = null
796     * StringUtils.join([], *)                 = ""
797     * StringUtils.join([null], *)             = ""
798     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
799     * StringUtils.join([1, 2, 3], null) = "123"
800     * </pre>
801     *
802     * @param array
803     *            the array of values to join together, may be null
804     * @param separator
805     *            the separator character to use
806     * @param startIndex
807     *            the first index to start joining from. It is an error to pass in an end index past the end of the
808     *            array
809     * @param endIndex
810     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
811     *            the array
812     * @return the joined String, {@code null} if null array input
813     * @since 3.2
814     */
815    public static String join(final char[] array, final char separator, final int startIndex, final int endIndex) {
816        if (array == null) {
817            return null;
818        }
819        final int noOfItems = endIndex - startIndex;
820        if (noOfItems <= 0) {
821            return EMPTY;
822        }
823        final StringBuilder buf = new StringBuilder(noOfItems * 16);
824        for (int i = startIndex; i < endIndex; i++) {
825            if (i > startIndex) {
826                buf.append(separator);
827            }
828            buf.append(array[i]);
829        }
830        return buf.toString();
831    }
832
833    /**
834     * <p>
835     * Joins the elements of the provided array into a single String containing the provided list of elements.
836     * </p>
837     *
838     * <p>
839     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
840     * by empty strings.
841     * </p>
842     *
843     * <pre>
844     * StringUtils.join(null, *)               = null
845     * StringUtils.join([], *)                 = ""
846     * StringUtils.join([null], *)             = ""
847     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
848     * StringUtils.join([1, 2, 3], null) = "123"
849     * </pre>
850     *
851     * @param array
852     *            the array of values to join together, may be null
853     * @param separator
854     *            the separator character to use
855     * @param startIndex
856     *            the first index to start joining from. It is an error to pass in an end index past the end of the
857     *            array
858     * @param endIndex
859     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
860     *            the array
861     * @return the joined String, {@code null} if null array input
862     * @since 3.2
863     */
864    public static String join(final double[] array, final char separator, final int startIndex, final int endIndex) {
865        if (array == null) {
866            return null;
867        }
868        final int noOfItems = endIndex - startIndex;
869        if (noOfItems <= 0) {
870            return EMPTY;
871        }
872        final StringBuilder buf = new StringBuilder(noOfItems * 16);
873        for (int i = startIndex; i < endIndex; i++) {
874            if (i > startIndex) {
875                buf.append(separator);
876            }
877            buf.append(array[i]);
878        }
879        return buf.toString();
880    }
881
882    /**
883     * <p>
884     * Joins the elements of the provided array into a single String containing the provided list of elements.
885     * </p>
886     *
887     * <p>
888     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
889     * by empty strings.
890     * </p>
891     *
892     * <pre>
893     * StringUtils.join(null, *)               = null
894     * StringUtils.join([], *)                 = ""
895     * StringUtils.join([null], *)             = ""
896     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
897     * StringUtils.join([1, 2, 3], null) = "123"
898     * </pre>
899     *
900     * @param array
901     *            the array of values to join together, may be null
902     * @param separator
903     *            the separator character to use
904     * @param startIndex
905     *            the first index to start joining from. It is an error to pass in an end index past the end of the
906     *            array
907     * @param endIndex
908     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
909     *            the array
910     * @return the joined String, {@code null} if null array input
911     * @since 3.2
912     */
913    public static String join(final float[] array, final char separator, final int startIndex, final int endIndex) {
914        if (array == null) {
915            return null;
916        }
917        final int noOfItems = endIndex - startIndex;
918        if (noOfItems <= 0) {
919            return EMPTY;
920        }
921        final StringBuilder buf = new StringBuilder(noOfItems * 16);
922        for (int i = startIndex; i < endIndex; i++) {
923            if (i > startIndex) {
924                buf.append(separator);
925            }
926            buf.append(array[i]);
927        }
928        return buf.toString();
929    }
930
931
932    /**
933     * <p>Joins the elements of the provided array into a single String
934     * containing the provided list of elements.</p>
935     *
936     * <p>No delimiter is added before or after the list.
937     * A {@code null} separator is the same as an empty String ("").
938     * Null objects or empty strings within the array are represented by
939     * empty strings.</p>
940     *
941     * <pre>
942     * StringUtils.join(null, *)                = null
943     * StringUtils.join([], *)                  = ""
944     * StringUtils.join([null], *)              = ""
945     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
946     * StringUtils.join(["a", "b", "c"], null)  = "abc"
947     * StringUtils.join(["a", "b", "c"], "")    = "abc"
948     * StringUtils.join([null, "", "a"], ',')   = ",,a"
949     * </pre>
950     *
951     * @param array  the array of values to join together, may be null
952     * @param separator  the separator character to use, null treated as ""
953     * @return the joined String, {@code null} if null array input
954     */
955    public static String join(final Object[] array, final String separator) {
956        if (array == null) {
957            return null;
958        }
959        return join(array, separator, 0, array.length);
960    }
961
962    /**
963     * <p>Joins the elements of the provided array into a single String
964     * containing the provided list of elements.</p>
965     *
966     * <p>No delimiter is added before or after the list.
967     * A {@code null} separator is the same as an empty String ("").
968     * Null objects or empty strings within the array are represented by
969     * empty strings.</p>
970     *
971     * <pre>
972     * StringUtils.join(null, *, *, *)                = null
973     * StringUtils.join([], *, *, *)                  = ""
974     * StringUtils.join([null], *, *, *)              = ""
975     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
976     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
977     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
978     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
979     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
980     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
981     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
982     * </pre>
983     *
984     * @param array  the array of values to join together, may be null
985     * @param separator  the separator character to use, null treated as ""
986     * @param startIndex the first index to start joining from.
987     * @param endIndex the index to stop joining from (exclusive).
988     * @return the joined String, {@code null} if null array input; or the empty string
989     * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
990     * {@code endIndex - startIndex}
991     * @throws ArrayIndexOutOfBoundsException ife<br>
992     * {@code startIndex < 0} or <br>
993     * {@code startIndex >= array.length()} or <br>
994     * {@code endIndex < 0} or <br>
995     * {@code endIndex > array.length()}
996     */
997    public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) {
998        if (array == null) {
999            return null;
1000        }
1001        if (separator == null) {
1002            separator = EMPTY;
1003        }
1004
1005        // endIndex - startIndex > 0:   Len = NofStrings *(len(firstString) + len(separator))
1006        //           (Assuming that all Strings are roughly equally long)
1007        final int noOfItems = endIndex - startIndex;
1008        if (noOfItems <= 0) {
1009            return EMPTY;
1010        }
1011
1012        final StringBuilder buf = new StringBuilder(noOfItems * 16);
1013
1014        for (int i = startIndex; i < endIndex; i++) {
1015            if (i > startIndex) {
1016                buf.append(separator);
1017            }
1018            if (array[i] != null) {
1019                buf.append(array[i]);
1020            }
1021        }
1022        return buf.toString();
1023    }
1024
1025    /**
1026     * <p>Joins the elements of the provided {@code Iterator} into
1027     * a single String containing the provided elements.</p>
1028     *
1029     * <p>No delimiter is added before or after the list. Null objects or empty
1030     * strings within the iteration are represented by empty strings.</p>
1031     *
1032     * <p>See the examples here: {@link #join(Object[],char)}. </p>
1033     *
1034     * @param iterator  the {@code Iterator} of values to join together, may be null
1035     * @param separator  the separator character to use
1036     * @return the joined String, {@code null} if null iterator input
1037     * @since 2.0
1038     */
1039    public static String join(final Iterator<?> iterator, final char separator) {
1040
1041        // handle null, zero and one elements before building a buffer
1042        if (iterator == null) {
1043            return null;
1044        }
1045        if (!iterator.hasNext()) {
1046            return EMPTY;
1047        }
1048        final Object first = iterator.next();
1049        if (!iterator.hasNext()) {
1050            final String result = first != null ? first.toString() : "";
1051            return result;
1052        }
1053
1054        // two or more elements
1055        final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
1056        if (first != null) {
1057            buf.append(first);
1058        }
1059
1060        while (iterator.hasNext()) {
1061            buf.append(separator);
1062            final Object obj = iterator.next();
1063            if (obj != null) {
1064                buf.append(obj);
1065            }
1066        }
1067
1068        return buf.toString();
1069    }
1070
1071    /**
1072     * <p>Joins the elements of the provided {@code Iterator} into
1073     * a single String containing the provided elements.</p>
1074     *
1075     * <p>No delimiter is added before or after the list.
1076     * A {@code null} separator is the same as an empty String ("").</p>
1077     *
1078     * <p>See the examples here: {@link #join(Object[],String)}. </p>
1079     *
1080     * @param iterator  the {@code Iterator} of values to join together, may be null
1081     * @param separator  the separator character to use, null treated as ""
1082     * @return the joined String, {@code null} if null iterator input
1083     */
1084    public static String join(final Iterator<?> iterator, final String separator) {
1085
1086        // handle null, zero and one elements before building a buffer
1087        if (iterator == null) {
1088            return null;
1089        }
1090        if (!iterator.hasNext()) {
1091            return EMPTY;
1092        }
1093        final Object first = iterator.next();
1094        if (!iterator.hasNext()) {
1095            final String result = first != null ? first.toString() : "";
1096            return result;
1097        }
1098
1099        // two or more elements
1100        final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
1101        if (first != null) {
1102            buf.append(first);
1103        }
1104
1105        while (iterator.hasNext()) {
1106            if (separator != null) {
1107                buf.append(separator);
1108            }
1109            final Object obj = iterator.next();
1110            if (obj != null) {
1111                buf.append(obj);
1112            }
1113        }
1114        return buf.toString();
1115    }
1116
1117    /**
1118     * <p>Joins the elements of the provided {@code Iterable} into
1119     * a single String containing the provided elements.</p>
1120     *
1121     * <p>No delimiter is added before or after the list. Null objects or empty
1122     * strings within the iteration are represented by empty strings.</p>
1123     *
1124     * <p>See the examples here: {@link #join(Object[],char)}. </p>
1125     *
1126     * @param iterable  the {@code Iterable} providing the values to join together, may be null
1127     * @param separator  the separator character to use
1128     * @return the joined String, {@code null} if null iterator input
1129     * @since 2.3
1130     */
1131    public static String join(final Iterable<?> iterable, final char separator) {
1132        if (iterable == null) {
1133            return null;
1134        }
1135        return join(iterable.iterator(), separator);
1136    }
1137
1138    /**
1139     * <p>Joins the elements of the provided {@code Iterable} into
1140     * a single String containing the provided elements.</p>
1141     *
1142     * <p>No delimiter is added before or after the list.
1143     * A {@code null} separator is the same as an empty String ("").</p>
1144     *
1145     * <p>See the examples here: {@link #join(Object[],String)}. </p>
1146     *
1147     * @param iterable  the {@code Iterable} providing the values to join together, may be null
1148     * @param separator  the separator character to use, null treated as ""
1149     * @return the joined String, {@code null} if null iterator input
1150     * @since 2.3
1151     */
1152    public static String join(final Iterable<?> iterable, final String separator) {
1153        if (iterable == null) {
1154            return null;
1155        }
1156        return join(iterable.iterator(), separator);
1157    }
1158
1159
1160    /**
1161     * <p>Checks if the CharSequence contains only Unicode digits.
1162     * A decimal point is not a Unicode digit and returns false.</p>
1163     *
1164     * <p>{@code null} will return {@code false}.
1165     * An empty CharSequence (length()=0) will return {@code false}.</p>
1166     *
1167     * <p>Note that the method does not allow for a leading sign, either positive or negative.
1168     * Also, if a String passes the numeric test, it may still generate a NumberFormatException
1169     * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
1170     * for int or long respectively.</p>
1171     *
1172     * <pre>
1173     * StringUtils.isNumeric(null)   = false
1174     * StringUtils.isNumeric("")     = false
1175     * StringUtils.isNumeric("  ")   = false
1176     * StringUtils.isNumeric("123")  = true
1177     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
1178     * StringUtils.isNumeric("12 3") = false
1179     * StringUtils.isNumeric("ab2c") = false
1180     * StringUtils.isNumeric("12-3") = false
1181     * StringUtils.isNumeric("12.3") = false
1182     * StringUtils.isNumeric("-123") = false
1183     * StringUtils.isNumeric("+123") = false
1184     * </pre>
1185     *
1186     * @param cs  the CharSequence to check, may be null
1187     * @return {@code true} if only contains digits, and is non-null
1188     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
1189     * @since 3.0 Changed "" to return false and not true
1190     */
1191    public static boolean isNumeric(final CharSequence cs) {
1192        if (cs == null || cs.length() == 0) {
1193            return false;
1194        }
1195        final int sz = cs.length();
1196        for (int i = 0; i < sz; i++) {
1197            if (!Character.isDigit(cs.charAt(i))) {
1198                return false;
1199            }
1200        }
1201        return true;
1202    }
1203
1204
1205    // startsWith
1206    //-----------------------------------------------------------------------
1207
1208    /**
1209     * <p>Check if a CharSequence starts with a specified prefix.</p>
1210     *
1211     * <p>{@code null}s are handled without exceptions. Two {@code null}
1212     * references are considered to be equal. The comparison is case sensitive.</p>
1213     *
1214     * <pre>
1215     * StringUtils.startsWith(null, null)      = true
1216     * StringUtils.startsWith(null, "abc")     = false
1217     * StringUtils.startsWith("abcdef", null)  = false
1218     * StringUtils.startsWith("abcdef", "abc") = true
1219     * StringUtils.startsWith("ABCDEF", "abc") = false
1220     * </pre>
1221     *
1222     * @see java.lang.String#startsWith(String)
1223     * @param str  the CharSequence to check, may be null
1224     * @param prefix the prefix to find, may be null
1225     * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or
1226     *  both {@code null}
1227     * @since 2.4
1228     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
1229     */
1230    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
1231        return startsWith(str, prefix, false);
1232    }
1233
1234    /**
1235     * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p>
1236     *
1237     * <p>{@code null}s are handled without exceptions. Two {@code null}
1238     * references are considered to be equal. The comparison is case insensitive.</p>
1239     *
1240     * <pre>
1241     * StringUtils.startsWithIgnoreCase(null, null)      = true
1242     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
1243     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
1244     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
1245     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
1246     * </pre>
1247     *
1248     * @see java.lang.String#startsWith(String)
1249     * @param str  the CharSequence to check, may be null
1250     * @param prefix the prefix to find, may be null
1251     * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or
1252     *  both {@code null}
1253     * @since 2.4
1254     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
1255     */
1256    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
1257        return startsWith(str, prefix, true);
1258    }
1259
1260    /**
1261     * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p>
1262     *
1263     * @see java.lang.String#startsWith(String)
1264     * @param str  the CharSequence to check, may be null
1265     * @param prefix the prefix to find, may be null
1266     * @param ignoreCase indicates whether the compare should ignore case
1267     *  (case insensitive) or not.
1268     * @return {@code true} if the CharSequence starts with the prefix or
1269     *  both {@code null}
1270     */
1271    private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
1272        if (str == null || prefix == null) {
1273            return str == null && prefix == null;
1274        }
1275        if (prefix.length() > str.length()) {
1276            return false;
1277        }
1278        return regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length());
1279    }
1280
1281    /**
1282     * Green implementation of regionMatches.
1283     *
1284     * @param cs the {@code CharSequence} to be processed
1285     * @param ignoreCase whether or not to be case insensitive
1286     * @param thisStart the index to start on the {@code cs} CharSequence
1287     * @param substring the {@code CharSequence} to be looked for
1288     * @param start the index to start on the {@code substring} CharSequence
1289     * @param length character length of the region
1290     * @return whether the region matched
1291     */
1292    static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart,
1293                                 final CharSequence substring, final int start, final int length)    {
1294        if (cs instanceof String && substring instanceof String) {
1295            return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length);
1296        }
1297        int index1 = thisStart;
1298        int index2 = start;
1299        int tmpLen = length;
1300
1301        // Extract these first so we detect NPEs the same as the java.lang.String version
1302        final int srcLen = cs.length() - thisStart;
1303        final int otherLen = substring.length() - start;
1304
1305        // Check for invalid parameters
1306        if (thisStart < 0 || start < 0 || length < 0) {
1307            return false;
1308        }
1309
1310        // Check that the regions are long enough
1311        if (srcLen < length || otherLen < length) {
1312            return false;
1313        }
1314
1315        while (tmpLen-- > 0) {
1316            final char c1 = cs.charAt(index1++);
1317            final char c2 = substring.charAt(index2++);
1318
1319            if (c1 == c2) {
1320                continue;
1321            }
1322
1323            if (!ignoreCase) {
1324                return false;
1325            }
1326
1327            // The same check as in String.regionMatches():
1328            if (Character.toUpperCase(c1) != Character.toUpperCase(c2)
1329                    && Character.toLowerCase(c1) != Character.toLowerCase(c2)) {
1330                return false;
1331            }
1332        }
1333
1334        return true;
1335    }
1336
1337    /**
1338     * The index value when an element is not found in a list or array: <code>-1</code>.
1339     * This value is returned by methods in this class and can also be used in comparisons with values returned by
1340     * various method from {@link java.util.List}.
1341     */
1342    public static final int INDEX_NOT_FOUND = -1;
1343
1344    // IndexOf search
1345    // ----------------------------------------------------------------------
1346
1347    // Object IndexOf
1348    //-----------------------------------------------------------------------
1349    /**
1350     * <p>Finds the index of the given object in the array.</p>
1351     *
1352     * <p>This method returns {@link #INDEX_NOT_FOUND} (<code>-1</code>) for a <code>null</code> input array.</p>
1353     *
1354     * @param array  the array to search through for the object, may be <code>null</code>
1355     * @param objectToFind  the object to find, may be <code>null</code>
1356     * @return the index of the object within the array,
1357     *  {@link #INDEX_NOT_FOUND} (<code>-1</code>) if not found or <code>null</code> array input
1358     */
1359    public static int indexOf(Object[] array, Object objectToFind) {
1360        return indexOf(array, objectToFind, 0);
1361    }
1362
1363    /**
1364     * <p>Finds the index of the given object in the array starting at the given index.</p>
1365     *
1366     * <p>This method returns {@link #INDEX_NOT_FOUND} (<code>-1</code>) for a <code>null</code> input array.</p>
1367     *
1368     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
1369     * length will return {@link #INDEX_NOT_FOUND} (<code>-1</code>).</p>
1370     *
1371     * @param array  the array to search through for the object, may be <code>null</code>
1372     * @param objectToFind  the object to find, may be <code>null</code>
1373     * @param startIndex  the index to start searching at
1374     * @return the index of the object within the array starting at the index,
1375     *  {@link #INDEX_NOT_FOUND} (<code>-1</code>) if not found or <code>null</code> array input
1376     */
1377    public static int indexOf(Object[] array, Object objectToFind, int startIndex) {
1378        if (array == null) {
1379            return INDEX_NOT_FOUND;
1380        }
1381        if (startIndex < 0) {
1382            startIndex = 0;
1383        }
1384        if (objectToFind == null) {
1385            for (int i = startIndex; i < array.length; i++) {
1386                if (array[i] == null) {
1387                    return i;
1388                }
1389            }
1390        } else {
1391            for (int i = startIndex; i < array.length; i++) {
1392                if (objectToFind.equals(array[i])) {
1393                    return i;
1394                }
1395            }
1396        }
1397        return INDEX_NOT_FOUND;
1398    }
1399}