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