1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.core.compiler;
14 * This class is a collection of helper methods to manipulate char arrays.
18 public final class CharOperation {
21 * Constant for an empty char array
23 public static final char[] NO_CHAR = new char[0];
26 * Constant for an empty char array with two dimensions.
28 public static final char[][] NO_CHAR_CHAR = new char[0][];
31 * Answers a new array with appending the suffix character at the end of the
39 * array = { 'a', 'b' }
41 * => result = { 'a', 'b' , 'c' }
50 * => result = { 'c' }
57 * the array that is concanated with the suffix character
59 * the suffix character
60 * @return the new array
62 public static final char[] append(char[] array, char suffix) {
64 return new char[] { suffix };
65 int length = array.length;
66 System.arraycopy(array, 0, array = new char[length + 1], 0, length);
67 array[length] = suffix;
72 * Append the given subarray to append to the target array starting at the
73 * given index in the target array. The start of the subarray is inclusive,
74 * the end is exclusive. Answers a new target array if it needs to grow,
75 * otherwise answers the same target array. <br>
81 * target = { 'a', 'b', -1 }
83 * array = { 'c', 'd' }
86 * => result = { 'a', 'b' , 'c' }
93 * target = { 'a', 'b' }
95 * array = { 'c', 'd' }
98 * => result = new { 'a', 'b' , 'c', -1 }
105 * target = { 'a', 'b', 'c' }
107 * array = { 'c', 'd', 'e', 'f' }
110 * => result = new { 'a', 'd' , 'e', 'f', -1, -1 }
116 public static final char[] append(char[] target, int index, char[] array,
117 int start, int end) {
118 int targetLength = target.length;
119 int subLength = end - start;
120 int newTargetLength = subLength + index;
121 if (newTargetLength > targetLength) {
122 System.arraycopy(target, 0, target = new char[newTargetLength * 2],
125 System.arraycopy(array, start, target, index, subLength);
130 * Answers the concatenation of the two arrays. It answers null if the two
131 * arrays are null. If the first array is null, then the second array is
132 * returned. If the second array is null, then the first array is returned.
142 * => result = null
149 * first = { { ' a' } }
151 * => result = { { ' a' } }
159 * second = { { ' a' } }
160 * => result = { { ' a' } }
167 * first = { { ' b' } }
168 * second = { { ' a' } }
169 * => result = { { ' b' }, { ' a' } }
176 * the first array to concatenate
178 * the second array to concatenate
179 * @return the concatenation of the two arrays, or null if the two arrays
182 public static final char[][] arrayConcat(char[][] first, char[][] second) {
188 int length1 = first.length;
189 int length2 = second.length;
190 char[][] result = new char[length1 + length2][];
191 System.arraycopy(first, 0, result, 0, length1);
192 System.arraycopy(second, 0, result, length1, length2);
197 * Answers a new array adding the second array at the end of first array. It
198 * answers null if the first and second are null. If the first array is
199 * null, then a new array char[][] is created with second. If the second
200 * array is null, then the first array is returned. <br>
209 * => result = { { ' a' } }
215 * first = { { ' a' } }
217 * => result = { { ' a' } }
224 * first = { { ' a' } }
226 * => result = { { ' a' } , { ' b' } }
233 * the first array to concatenate
235 * the array to add at the end of the first array
236 * @return a new array adding the second array at the end of first array, or
237 * null if the two arrays are null.
239 public static final char[][] arrayConcat(char[][] first, char[] second) {
243 return new char[][] { second };
245 int length = first.length;
246 char[][] result = new char[length + 1][];
247 System.arraycopy(first, 0, result, 0, length);
248 result[length] = second;
253 * Answers the concatenation of the two arrays. It answers null if the two
254 * arrays are null. If the first array is null, then the second array is
255 * returned. If the second array is null, then the first array is returned.
265 * => result = { ' a' }
274 * => result = { ' a' }
283 * => result = { ' a' , ' b' }
290 * the first array to concatenate
292 * the second array to concatenate
293 * @return the concatenation of the two arrays, or null if the two arrays
296 public static final char[] concat(char[] first, char[] second) {
302 int length1 = first.length;
303 int length2 = second.length;
304 char[] result = new char[length1 + length2];
305 System.arraycopy(first, 0, result, 0, length1);
306 System.arraycopy(second, 0, result, length1, length2);
311 * Answers the concatenation of the three arrays. It answers null if the
312 * three arrays are null. If first is null, it answers the concatenation of
313 * second and third. If second is null, it answers the concatenation of
314 * first and third. If third is null, it answers the concatenation of first
325 * => result = { ' a', 'b' }
335 * => result = { ' a', 'b' }
345 * => result = { ' a', 'b' }
355 * => result = null
365 * => result = { 'a', 'b', 'c' }
372 * the first array to concatenate
374 * the second array to concatenate
376 * the third array to concatenate
378 * @return the concatenation of the three arrays, or null if the three
381 public static final char[] concat(char[] first, char[] second, char[] third) {
383 return concat(second, third);
385 return concat(first, third);
387 return concat(first, second);
389 int length1 = first.length;
390 int length2 = second.length;
391 int length3 = third.length;
392 char[] result = new char[length1 + length2 + length3];
393 System.arraycopy(first, 0, result, 0, length1);
394 System.arraycopy(second, 0, result, length1, length2);
395 System.arraycopy(third, 0, result, length1 + length2, length3);
400 * Answers the concatenation of the two arrays inserting the separator
401 * character between the two arrays. It answers null if the two arrays are
402 * null. If the first array is null, then the second array is returned. If
403 * the second array is null, then the first array is returned. <br>
413 * => result = { ' a' }
423 * => result = { ' a' }
433 * => result = { ' a' , '/', 'b' }
440 * the first array to concatenate
442 * the second array to concatenate
444 * the character to insert
445 * @return the concatenation of the two arrays inserting the separator
446 * character between the two arrays , or null if the two arrays are
449 public static final char[] concat(char[] first, char[] second,
456 int length1 = first.length;
459 int length2 = second.length;
463 char[] result = new char[length1 + length2 + 1];
464 System.arraycopy(first, 0, result, 0, length1);
465 result[length1] = separator;
466 System.arraycopy(second, 0, result, length1 + 1, length2);
471 * Answers the concatenation of the three arrays inserting the sep1
472 * character between the two arrays and sep2 between the last two. It
473 * answers null if the three arrays are null. If the first array is null,
474 * then it answers the concatenation of second and third inserting the sep2
475 * character between them. If the second array is null, then the first array
486 * => result = { ' a' }
496 * => result = { ' a' }
506 * => result = { ' a' , '/', 'b' }
513 * the first array to concatenate
515 * the second array to concatenate
517 * the character to insert
518 * @return the concatenation of the two arrays inserting the separator
519 * character between the two arrays , or null if the two arrays are
522 public static final char[] concat(char[] first, char sep1, char[] second,
523 char sep2, char[] third) {
525 return concat(second, third, sep2);
527 return concat(first, third, sep1);
529 return concat(first, second, sep1);
531 int length1 = first.length;
532 int length2 = second.length;
533 int length3 = third.length;
534 char[] result = new char[length1 + length2 + length3 + 2];
535 System.arraycopy(first, 0, result, 0, length1);
536 result[length1] = sep1;
537 System.arraycopy(second, 0, result, length1 + 1, length2);
538 result[length1 + length2 + 1] = sep2;
539 System.arraycopy(third, 0, result, length1 + length2 + 2, length3);
544 * Answers a new array with prepending the prefix character and appending
545 * the suffix character at the end of the array. If array is null, it
546 * answers a new array containing the prefix and the suffix characters. <br>
556 * => result = { 'a', 'b' , 'c' }
566 * => result = { 'a', 'c' }
573 * the prefix character
575 * the array that is concanated with the prefix and suffix
578 * the suffix character
579 * @return the new array
581 public static final char[] concat(char prefix, char[] array, char suffix) {
583 return new char[] { prefix, suffix };
585 int length = array.length;
586 char[] result = new char[length + 2];
588 System.arraycopy(array, 0, result, 1, length);
589 result[length + 1] = suffix;
594 * Answers the concatenation of the given array parts using the given
595 * separator between each part and appending the given name at the end. <br>
603 * array = { { 'a' }, { 'b' } }
605 * => result = { 'a', '.', 'b' , '.', 'c' }
613 * array = { { 'a' }, { 'b' } }
615 * => result = { 'a', '.', 'b' }
625 * => result = { 'c' }
636 * the given separator
637 * @return the concatenation of the given array parts using the given
638 * separator between each part and appending the given name at the
641 public static final char[] concatWith(char[] name, char[][] array,
643 int nameLength = name == null ? 0 : name.length;
645 return concatWith(array, separator);
647 int length = array == null ? 0 : array.length;
651 int size = nameLength;
654 if (array[index].length > 0)
655 size += array[index].length + 1;
656 char[] result = new char[size];
658 for (int i = length - 1; i >= 0; i--) {
659 int subLength = array[i].length;
662 System.arraycopy(array[i], 0, result, index, subLength);
663 result[--index] = separator;
666 System.arraycopy(name, 0, result, 0, nameLength);
671 * Answers the concatenation of the given array parts using the given
672 * separator between each part and appending the given name at the end. <br>
680 * array = { { 'a' }, { 'b' } }
682 * => result = { 'a', '.', 'b' , '.', 'c' }
690 * array = { { 'a' }, { 'b' } }
692 * => result = { 'a', '.', 'b' }
702 * => result = { 'c' }
713 * the given separator
714 * @return the concatenation of the given array parts using the given
715 * separator between each part and appending the given name at the
718 public static final char[] concatWith(char[][] array, char[] name,
720 int nameLength = name == null ? 0 : name.length;
722 return concatWith(array, separator);
724 int length = array == null ? 0 : array.length;
728 int size = nameLength;
731 if (array[index].length > 0)
732 size += array[index].length + 1;
733 char[] result = new char[size];
735 for (int i = 0; i < length; i++) {
736 int subLength = array[i].length;
738 System.arraycopy(array[i], 0, result, index, subLength);
740 result[index++] = separator;
743 System.arraycopy(name, 0, result, index, nameLength);
748 * Answers the concatenation of the given array parts using the given
749 * separator between each part. <br>
756 * array = { { 'a' }, { 'b' } }
758 * => result = { 'a', '.', 'b' }
776 * the given separator
777 * @return the concatenation of the given array parts using the given
778 * separator between each part
780 public static final char[] concatWith(char[][] array, char separator) {
781 int length = array == null ? 0 : array.length;
783 return CharOperation.NO_CHAR;
785 int size = length - 1;
787 while (--index >= 0) {
788 if (array[index].length == 0)
791 size += array[index].length;
794 return CharOperation.NO_CHAR;
795 char[] result = new char[size];
797 while (--index >= 0) {
798 length = array[index].length;
800 System.arraycopy(array[index], 0, result, (size -= length),
803 result[size] = separator;
810 * Answers true if the array contains an occurrence of character, false
821 * array = { { ' a' }, { ' b' } }
830 * array = { { ' a' }, { ' b' } }
838 * the character to search
840 * the array in which the search is done
841 * @exception NullPointerException
844 * @return true if the array contains an occurrence of character, false
847 public static final boolean contains(char character, char[][] array) {
848 for (int i = array.length; --i >= 0;) {
849 char[] subarray = array[i];
850 for (int j = subarray.length; --j >= 0;)
851 if (subarray[j] == character)
858 * Answers true if the array contains an occurrence of character, false
878 * array = { ' a' , ' b' }
886 * the character to search
888 * the array in which the search is done
889 * @exception NullPointerException
892 * @return true if the array contains an occurrence of character, false
895 public static final boolean contains(char character, char[] array) {
896 for (int i = array.length; --i >= 0;)
897 if (array[i] == character)
903 * Answers a deep copy of the toCopy array.
907 * @return a deep copy of the toCopy array.
909 public static final char[][] deepCopy(char[][] toCopy) {
910 int toCopyLength = toCopy.length;
911 char[][] result = new char[toCopyLength][];
912 for (int i = 0; i < toCopyLength; i++) {
913 char[] toElement = toCopy[i];
914 int toElementLength = toElement.length;
915 char[] resultElement = new char[toElementLength];
916 System.arraycopy(toElement, 0, resultElement, 0, toElementLength);
917 result[i] = resultElement;
923 * Return true if array ends with the sequence of characters contained in
924 * toBeFound, otherwise false. <br>
931 * array = { 'a', 'b', 'c', 'd' }
932 * toBeFound = { 'b', 'c' }
940 * array = { 'a', 'b', 'c' }
941 * toBeFound = { 'b', 'c' }
952 * @exception NullPointerException
953 * if array is null or toBeFound is null
954 * @return true if array ends with the sequence of characters contained in
955 * toBeFound, otherwise false.
957 public static final boolean endsWith(char[] array, char[] toBeFound) {
958 int i = toBeFound.length;
959 int j = array.length - i;
964 if (toBeFound[i] != array[i + j])
970 * Answers true if the two arrays are identical character by character,
971 * otherwise false. The equality is case sensitive. <br>
996 * first = { { 'a' } }
997 * second = { { 'a' } }
1005 * first = { { 'A' } }
1006 * second = { { 'a' } }
1007 * result => false
1017 * @return true if the two arrays are identical character by character,
1020 public static final boolean equals(char[][] first, char[][] second) {
1021 if (first == second)
1023 if (first == null || second == null)
1025 if (first.length != second.length)
1028 for (int i = first.length; --i >= 0;)
1029 if (!equals(first[i], second[i]))
1035 * If isCaseSensite is true, answers true if the two arrays are identical
1036 * character by character, otherwise false. If it is false, answers true if
1037 * the two arrays are identical character by character without checking the
1038 * case, otherwise false. <br>
1047 * isCaseSensitive = true
1057 * isCaseSensitive = true
1058 * result => false
1065 * first = { { 'A' } }
1066 * second = { { 'a' } }
1067 * isCaseSensitive = true
1068 * result => false
1075 * first = { { 'A' } }
1076 * second = { { 'a' } }
1077 * isCaseSensitive = false
1088 * @param isCaseSensitive
1089 * check whether or not the equality should be case sensitive
1090 * @return true if the two arrays are identical character by character
1091 * according to the value of isCaseSensitive, otherwise false
1093 public static final boolean equals(char[][] first, char[][] second,
1094 boolean isCaseSensitive) {
1096 if (isCaseSensitive) {
1097 return equals(first, second);
1099 if (first == second)
1101 if (first == null || second == null)
1103 if (first.length != second.length)
1106 for (int i = first.length; --i >= 0;)
1107 if (!equals(first[i], second[i], false))
1113 * Answers true if the two arrays are identical character by character,
1114 * otherwise false. The equality is case sensitive. <br>
1132 * result => false
1150 * result => false
1160 * @return true if the two arrays are identical character by character,
1163 public static final boolean equals(char[] first, char[] second) {
1164 if (first == second)
1166 if (first == null || second == null)
1168 if (first.length != second.length)
1171 for (int i = first.length; --i >= 0;)
1172 if (first[i] != second[i])
1178 * If isCaseSensite is true, answers true if the two arrays are identical
1179 * character by character, otherwise false. If it is false, answers true if
1180 * the two arrays are identical character by character without checking the
1181 * case, otherwise false. <br>
1190 * isCaseSensitive = true
1200 * isCaseSensitive = true
1201 * result => false
1210 * isCaseSensitive = true
1211 * result => false
1220 * isCaseSensitive = false
1231 * @param isCaseSensitive
1232 * check whether or not the equality should be case sensitive
1233 * @return true if the two arrays are identical character by character
1234 * according to the value of isCaseSensitive, otherwise false
1236 public static final boolean equals(char[] first, char[] second,
1237 boolean isCaseSensitive) {
1239 if (isCaseSensitive) {
1240 return equals(first, second);
1242 if (first == second)
1244 if (first == null || second == null)
1246 if (first.length != second.length)
1249 for (int i = first.length; --i >= 0;)
1250 if (Character.toLowerCase(first[i]) != Character
1251 .toLowerCase(second[i]))
1257 * If isCaseSensite is true, the equality is case sensitive, otherwise it is
1260 * Answers true if the name contains the fragment at the starting index
1261 * startIndex, otherwise false. <br>
1268 * fragment = { 'b', 'c' , 'd' }
1269 * name = { 'a', 'b', 'c' , 'd' }
1271 * isCaseSensitive = true
1279 * fragment = { 'b', 'c' , 'd' }
1280 * name = { 'a', 'b', 'C' , 'd' }
1282 * isCaseSensitive = true
1283 * result => false
1290 * fragment = { 'b', 'c' , 'd' }
1291 * name = { 'a', 'b', 'C' , 'd' }
1293 * isCaseSensitive = false
1294 * result => false
1301 * fragment = { 'b', 'c' , 'd' }
1302 * name = { 'a', 'b'}
1304 * isCaseSensitive = true
1305 * result => false
1312 * the fragment to check
1314 * the array to check
1316 * the starting index
1317 * @param isCaseSensitive
1318 * check whether or not the equality should be case sensitive
1319 * @return true if the name contains the fragment at the starting index
1320 * startIndex according to the value of isCaseSensitive, otherwise
1322 * @exception NullPointerException
1323 * if fragment or name is null.
1325 public static final boolean fragmentEquals(char[] fragment, char[] name,
1326 int startIndex, boolean isCaseSensitive) {
1328 int max = fragment.length;
1329 if (name.length < max + startIndex)
1331 if (isCaseSensitive) {
1332 for (int i = max; --i >= 0;)
1333 // assumes the prefix is not larger than the name
1334 if (fragment[i] != name[i + startIndex])
1338 for (int i = max; --i >= 0;)
1339 // assumes the prefix is not larger than the name
1340 if (Character.toLowerCase(fragment[i]) != Character
1341 .toLowerCase(name[i + startIndex]))
1347 * Answers a hashcode for the array
1350 * the array for which a hashcode is required
1351 * @return the hashcode
1352 * @exception NullPointerException
1355 public static final int hashCode(char[] array) {
1358 int length = array.length;
1360 for (int i = length; i > 0; i--)
1361 hash = (hash * 37) + array[offset++];
1363 // only sample some characters
1364 int skip = length / 8;
1365 for (int i = length; i > 0; i -= skip, offset += skip)
1366 hash = (hash * 39) + array[offset];
1368 return hash & 0x7FFFFFFF;
1372 * Answers true if c is a whitespace according to the JLS (\u000a,
1373 * \u000c, \u000d, \u0009), otherwise false. <br>
1389 * result => false
1396 * the character to check
1397 * @return true if c is a whitespace according to the JLS, otherwise false.
1399 public static boolean isWhitespace(char c) {
1401 case 10: /* \ u000a: LINE FEED */
1402 case 12: /* \ u000c: FORM FEED */
1403 case 13: /* \ u000d: CARRIAGE RETURN */
1404 case 32: /* \ u0020: SPACE */
1405 case 9: /* \ u0009: HORIZONTAL TABULATION */
1413 * Answers the first index in the array for which the corresponding
1414 * character is equal to toBeFound. Answers -1 if no occurrence of this
1415 * character is found. <br>
1423 * array = { ' a', 'b', 'c', 'd' }
1432 * array = { ' a', 'b', 'c', 'd' }
1440 * the character to search
1442 * the array to be searched
1443 * @return the first index in the array for which the corresponding
1444 * character is equal to toBeFound, -1 otherwise
1445 * @exception NullPointerException
1448 public static final int indexOf(char toBeFound, char[] array) {
1449 for (int i = 0; i < array.length; i++)
1450 if (toBeFound == array[i])
1456 * Answers the first index in the array for which the corresponding
1457 * character is equal to toBeFound starting the search at index start.
1458 * Answers -1 if no occurrence of this character is found. <br>
1466 * array = { ' a', 'b', 'c', 'd' }
1476 * array = { ' a', 'b', 'c', 'd' }
1486 * array = { ' a', 'b', 'c', 'd' }
1495 * the character to search
1497 * the array to be searched
1499 * the starting index
1500 * @return the first index in the array for which the corresponding
1501 * character is equal to toBeFound, -1 otherwise
1502 * @exception NullPointerException
1504 * @exception ArrayIndexOutOfBoundsException
1505 * if start is lower than 0
1507 public static final int indexOf(char toBeFound, char[] array, int start) {
1508 for (int i = start; i < array.length; i++)
1509 if (toBeFound == array[i])
1515 * Answers the last index in the array for which the corresponding character
1516 * is equal to toBeFound starting from the end of the array. Answers -1 if
1517 * no occurrence of this character is found. <br>
1525 * array = { ' a', 'b', 'c', 'd' , 'c', 'e' }
1534 * array = { ' a', 'b', 'c', 'd' }
1542 * the character to search
1544 * the array to be searched
1545 * @return the last index in the array for which the corresponding character
1546 * is equal to toBeFound starting from the end of the array, -1
1548 * @exception NullPointerException
1551 public static final int lastIndexOf(char toBeFound, char[] array) {
1552 for (int i = array.length; --i >= 0;)
1553 if (toBeFound == array[i])
1559 * Answers the last index in the array for which the corresponding character
1560 * is equal to toBeFound stopping at the index startIndex. Answers -1 if no
1561 * occurrence of this character is found. <br>
1569 * array = { ' a', 'b', 'c', 'd' }
1579 * array = { ' a', 'b', 'c', 'd', 'e' }
1589 * array = { ' a', 'b', 'c', 'd' }
1598 * the character to search
1600 * the array to be searched
1602 * the stopping index
1603 * @return the last index in the array for which the corresponding character
1604 * is equal to toBeFound stopping at the index startIndex, -1
1606 * @exception NullPointerException
1608 * @exception ArrayIndexOutOfBoundsException
1609 * if startIndex is lower than 0
1611 public static final int lastIndexOf(char toBeFound, char[] array,
1613 for (int i = array.length; --i >= startIndex;)
1614 if (toBeFound == array[i])
1620 * Answers the last index in the array for which the corresponding character
1621 * is equal to toBeFound starting from endIndex to startIndex. Answers -1 if
1622 * no occurrence of this character is found. <br>
1630 * array = { ' a', 'b', 'c', 'd' }
1641 * array = { ' a', 'b', 'c', 'd', 'e' }
1652 * array = { ' a', 'b', 'c', 'd' }
1662 * the character to search
1664 * the array to be searched
1666 * the stopping index
1668 * the starting index
1669 * @return the last index in the array for which the corresponding character
1670 * is equal to toBeFound starting from endIndex to startIndex, -1
1672 * @exception NullPointerException
1674 * @exception ArrayIndexOutOfBoundsException
1675 * if endIndex is greater or equals to array length or
1676 * starting is lower than 0
1678 public static final int lastIndexOf(char toBeFound, char[] array,
1679 int startIndex, int endIndex) {
1680 for (int i = endIndex; --i >= startIndex;)
1681 if (toBeFound == array[i])
1687 * Answers the last portion of a name given a separator. <br>
1692 * lastSegment("java.lang.Object".toCharArray(),'.') --> Object
1698 * the given separator
1699 * @return the last portion of a name given a separator
1700 * @exception NullPointerException
1703 final static public char[] lastSegment(char[] array, char separator) {
1704 int pos = lastIndexOf(separator, array);
1707 return subarray(array, pos + 1, array.length);
1711 * Answers true if the pattern matches the given name, false otherwise. This
1712 * char[] pattern matching accepts wild-cards '*' and '?'.
1714 * When not case sensitive, the pattern is assumed to already be lowercased,
1715 * the name will be lowercased character per character as comparing. If name
1716 * is null, the answer is false. If pattern is null, the answer is true if
1717 * name is not null. <br>
1724 * pattern = { '?', 'b', '*' }
1725 * name = { 'a', 'b', 'c' , 'd' }
1726 * isCaseSensitive = true
1734 * pattern = { '?', 'b', '?' }
1735 * name = { 'a', 'b', 'c' , 'd' }
1736 * isCaseSensitive = true
1737 * result => false
1744 * pattern = { 'b', '*' }
1745 * name = { 'a', 'b', 'c' , 'd' }
1746 * isCaseSensitive = true
1747 * result => false
1757 * @param isCaseSensitive
1758 * flag to know whether or not the matching should be case
1760 * @return true if the pattern matches the given name, false otherwise
1762 public static final boolean match(char[] pattern, char[] name,
1763 boolean isCaseSensitive) {
1766 return false; // null name cannot match
1767 if (pattern == null)
1768 return true; // null pattern is equivalent to '*'
1770 return match(pattern, 0, pattern.length, name, 0, name.length,
1775 * Answers true if the a sub-pattern matches the subpart of the given name,
1776 * false otherwise. char[] pattern matching, accepting wild-cards '*' and
1777 * '?'. Can match only subset of name/pattern. end positions are
1778 * non-inclusive. The subpattern is defined by the patternStart and
1779 * pattternEnd positions. When not case sensitive, the pattern is assumed to
1780 * already be lowercased, the name will be lowercased character per
1781 * character as comparing. <br>
1788 * pattern = { '?', 'b', '*' }
1791 * name = { 'a', 'b', 'c' , 'd' }
1794 * isCaseSensitive = true
1802 * pattern = { '?', 'b', '*' }
1805 * name = { 'a', 'b', 'c' , 'd' }
1808 * isCaseSensitive = true
1809 * result => false
1817 * @param patternStart
1818 * the given pattern start
1820 * the given pattern end
1824 * the given name start
1826 * the given name end
1827 * @param isCaseSensitive
1828 * flag to know if the matching should be case sensitive
1829 * @return true if the a sub-pattern matches the subpart of the given name,
1832 public static final boolean match(char[] pattern, int patternStart,
1833 int patternEnd, char[] name, int nameStart, int nameEnd,
1834 boolean isCaseSensitive) {
1837 return false; // null name cannot match
1838 if (pattern == null)
1839 return true; // null pattern is equivalent to '*'
1840 int iPattern = patternStart;
1841 int iName = nameStart;
1844 patternEnd = pattern.length;
1846 nameEnd = name.length;
1848 /* check first segment */
1849 char patternChar = 0;
1850 while ((iPattern < patternEnd)
1851 && (patternChar = pattern[iPattern]) != '*') {
1852 if (iName == nameEnd)
1854 if (patternChar != (isCaseSensitive ? name[iName] : Character
1855 .toLowerCase(name[iName]))
1856 && patternChar != '?') {
1862 /* check sequence of star+segment */
1864 if (patternChar == '*') {
1865 segmentStart = ++iPattern; // skip star
1867 segmentStart = 0; // force iName check
1869 int prefixStart = iName;
1870 checkSegment: while (iName < nameEnd) {
1871 if (iPattern == patternEnd) {
1872 iPattern = segmentStart; // mismatch - restart current
1874 iName = ++prefixStart;
1875 continue checkSegment;
1877 /* segment is ending */
1878 if ((patternChar = pattern[iPattern]) == '*') {
1879 segmentStart = ++iPattern; // skip start
1880 if (segmentStart == patternEnd) {
1883 prefixStart = iName;
1884 continue checkSegment;
1886 /* check current name character */
1887 if ((isCaseSensitive ? name[iName] : Character
1888 .toLowerCase(name[iName])) != patternChar
1889 && patternChar != '?') {
1890 iPattern = segmentStart; // mismatch - restart current
1892 iName = ++prefixStart;
1893 continue checkSegment;
1899 return (segmentStart == patternEnd)
1900 || (iName == nameEnd && iPattern == patternEnd)
1901 || (iPattern == patternEnd - 1 && pattern[iPattern] == '*');
1905 * Answers true if the pattern matches the filepath using the pathSepatator,
1908 * Path char[] pattern matching, accepting wild-cards '**', '*' and '?'
1909 * (using Ant directory tasks conventions, also see
1910 * "http://jakarta.apache.org/ant/manual/dirtasks.html#defaultexcludes").
1911 * Path pattern matching is enhancing regular pattern matching in supporting
1912 * extra rule where '**' represent any folder combination. Special rules: -
1913 * foo\ is equivalent to foo\** - *.php is equivalent to **\*.php When not
1914 * case sensitive, the pattern is assumed to already be lowercased, the name
1915 * will be lowercased character per character as comparing.
1921 * @param isCaseSensitive
1922 * to find out whether or not the matching should be case
1924 * @param pathSeparator
1925 * the given path separator
1926 * @return true if the pattern matches the filepath using the pathSepatator,
1929 public static final boolean pathMatch(char[] pattern, char[] filepath,
1930 boolean isCaseSensitive, char pathSeparator) {
1932 if (filepath == null)
1933 return false; // null name cannot match
1934 if (pattern == null)
1935 return true; // null pattern is equivalent to '*'
1937 // special case: pattern foo is equivalent to **\foo (not absolute)
1938 boolean freeLeadingDoubleStar;
1940 // offsets inside pattern
1941 int pSegmentStart, pLength = pattern.length;
1943 if (freeLeadingDoubleStar = pattern[0] != pathSeparator) {
1948 int pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
1950 if (pSegmentEnd < 0)
1951 pSegmentEnd = pLength;
1953 // special case: pattern foo\ is equivalent to foo\**
1954 boolean freeTrailingDoubleStar = pattern[pLength - 1] == pathSeparator;
1956 // offsets inside filepath
1957 int fSegmentStart, fLength = filepath.length;
1958 if (filepath[0] != pathSeparator) {
1963 if (fSegmentStart != pSegmentStart) {
1964 return false; // both must start with a separator or none.
1966 int fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath,
1968 if (fSegmentEnd < 0)
1969 fSegmentEnd = fLength;
1972 while (pSegmentStart < pLength
1973 && !freeLeadingDoubleStar
1974 && !(pSegmentEnd == pLength && freeTrailingDoubleStar || (pSegmentEnd == pSegmentStart + 2
1975 && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*'))) {
1977 if (fSegmentStart >= fLength)
1979 if (!CharOperation.match(pattern, pSegmentStart, pSegmentEnd,
1980 filepath, fSegmentStart, fSegmentEnd, isCaseSensitive)) {
1984 // jump to next segment
1985 pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
1986 pSegmentStart = pSegmentEnd + 1);
1988 if (pSegmentEnd < 0)
1989 pSegmentEnd = pLength;
1991 fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath,
1992 fSegmentStart = fSegmentEnd + 1);
1994 if (fSegmentEnd < 0)
1995 fSegmentEnd = fLength;
1998 /* check sequence of doubleStar+segment */
1999 int pSegmentRestart;
2000 if ((pSegmentStart >= pLength && freeTrailingDoubleStar)
2001 || (pSegmentEnd == pSegmentStart + 2
2002 && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*')) {
2003 pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
2004 pSegmentStart = pSegmentEnd + 1);
2006 if (pSegmentEnd < 0)
2007 pSegmentEnd = pLength;
2008 pSegmentRestart = pSegmentStart;
2010 pSegmentRestart = 0; // force fSegmentStart check
2012 int fSegmentRestart = fSegmentStart;
2013 checkSegment: while (fSegmentStart < fLength) {
2015 if (pSegmentStart >= pLength) {
2016 if (freeTrailingDoubleStar)
2018 // mismatch - restart current path segment
2019 pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
2020 pSegmentStart = pSegmentRestart);
2021 if (pSegmentEnd < 0)
2022 pSegmentEnd = pLength;
2024 fSegmentRestart = CharOperation.indexOf(pathSeparator,
2025 filepath, fSegmentRestart + 1);
2027 if (fSegmentRestart < 0) {
2028 fSegmentRestart = fLength;
2032 fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath,
2033 fSegmentStart = fSegmentRestart);
2034 if (fSegmentEnd < 0)
2035 fSegmentEnd = fLength;
2036 continue checkSegment;
2039 /* path segment is ending */
2040 if (pSegmentEnd == pSegmentStart + 2
2041 && pattern[pSegmentStart] == '*'
2042 && pattern[pSegmentStart + 1] == '*') {
2043 pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
2044 pSegmentStart = pSegmentEnd + 1);
2046 if (pSegmentEnd < 0)
2047 pSegmentEnd = pLength;
2048 pSegmentRestart = pSegmentStart;
2049 fSegmentRestart = fSegmentStart;
2050 if (pSegmentStart >= pLength)
2052 continue checkSegment;
2054 /* chech current path segment */
2055 if (!CharOperation.match(pattern, pSegmentStart, pSegmentEnd,
2056 filepath, fSegmentStart, fSegmentEnd, isCaseSensitive)) {
2057 // mismatch - restart current path segment
2058 pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
2059 pSegmentStart = pSegmentRestart);
2060 if (pSegmentEnd < 0)
2061 pSegmentEnd = pLength;
2063 fSegmentRestart = CharOperation.indexOf(pathSeparator,
2064 filepath, fSegmentRestart + 1);
2066 if (fSegmentRestart < 0) {
2067 fSegmentRestart = fLength;
2071 fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath,
2072 fSegmentStart = fSegmentRestart);
2073 if (fSegmentEnd < 0)
2074 fSegmentEnd = fLength;
2075 continue checkSegment;
2077 // jump to next segment
2078 pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
2079 pSegmentStart = pSegmentEnd + 1);
2081 if (pSegmentEnd < 0)
2082 pSegmentEnd = pLength;
2084 fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath,
2085 fSegmentStart = fSegmentEnd + 1);
2087 if (fSegmentEnd < 0)
2088 fSegmentEnd = fLength;
2091 return (pSegmentRestart >= pSegmentEnd)
2092 || (fSegmentStart >= fLength && pSegmentStart >= pLength)
2093 || (pSegmentStart == pLength - 2
2094 && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*')
2095 || (pSegmentStart == pLength && freeTrailingDoubleStar);
2099 * Answers the number of occurrences of the given character in the given
2110 * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2119 * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2127 * the given character
2130 * @return the number of occurrences of the given character in the given
2132 * @exception NullPointerException
2135 public static final int occurencesOf(char toBeFound, char[] array) {
2137 for (int i = 0; i < array.length; i++)
2138 if (toBeFound == array[i])
2144 * Answers the number of occurrences of the given character in the given
2145 * array starting at the given index, 0 if any.
2155 * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2165 * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2174 * the given character
2177 * @return the number of occurrences of the given character in the given
2179 * @exception NullPointerException
2181 * @exception ArrayIndexOutOfBoundsException
2182 * if start is lower than 0
2184 public static final int occurencesOf(char toBeFound, char[] array, int start) {
2186 for (int i = start; i < array.length; i++)
2187 if (toBeFound == array[i])
2193 * Answers true if the given name starts with the given prefix, false
2194 * otherwise. The comparison is case sensitive. <br>
2201 * prefix = { 'a' , 'b' }
2202 * name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2210 * prefix = { 'a' , 'c' }
2211 * name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2212 * result => false
2222 * @return true if the given name starts with the given prefix, false
2224 * @exception NullPointerException
2225 * if the given name is null or if the given prefix is null
2227 public static final boolean prefixEquals(char[] prefix, char[] name) {
2229 int max = prefix.length;
2230 if (name.length < max)
2232 for (int i = max; --i >= 0;)
2233 // assumes the prefix is not larger than the name
2234 if (prefix[i] != name[i])
2240 * Answers true if the given name starts with the given prefix, false
2241 * otherwise. isCaseSensitive is used to find out whether or not the
2242 * comparison should be case sensitive. <br>
2249 * prefix = { 'a' , 'B' }
2250 * name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2251 * isCaseSensitive = false
2259 * prefix = { 'a' , 'B' }
2260 * name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2261 * isCaseSensitive = true
2262 * result => false
2272 * @param isCaseSensitive
2273 * to find out whether or not the comparison should be case
2275 * @return true if the given name starts with the given prefix, false
2277 * @exception NullPointerException
2278 * if the given name is null or if the given prefix is null
2280 public static final boolean prefixEquals(char[] prefix, char[] name,
2281 boolean isCaseSensitive) {
2283 int max = prefix.length;
2284 if (name.length < max)
2286 if (isCaseSensitive) {
2287 for (int i = max; --i >= 0;)
2288 // assumes the prefix is not larger than the name
2289 if (prefix[i] != name[i])
2294 for (int i = max; --i >= 0;)
2295 // assumes the prefix is not larger than the name
2296 if (Character.toLowerCase(prefix[i]) != Character
2297 .toLowerCase(name[i]))
2303 * Replace all occurrence of the character to be replaced with the
2304 * remplacement character in the given array. <br>
2311 * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2312 * toBeReplaced = 'b'
2313 * replacementChar = 'a'
2314 * result => No returned value, but array is now equals to { 'a' , 'a', 'a', 'a', 'a', 'a' }
2321 * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2322 * toBeReplaced = 'c'
2323 * replacementChar = 'a'
2324 * result => No returned value, but array is now equals to { 'a' , 'b', 'b', 'a', 'b', 'a' }
2332 * @param toBeReplaced
2333 * the character to be replaced
2334 * @param replacementChar
2335 * the replacement character
2336 * @exception NullPointerException
2337 * if the given array is null
2339 public static final void replace(char[] array, char toBeReplaced,
2340 char replacementChar) {
2341 if (toBeReplaced != replacementChar) {
2342 for (int i = 0, max = array.length; i < max; i++) {
2343 if (array[i] == toBeReplaced)
2344 array[i] = replacementChar;
2350 * Answers a new array of characters with substitutions. No side-effect is
2351 * operated on the original array, in case no substitution happened, then
2352 * the result is the same as the original one. <br>
2359 * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2360 * toBeReplaced = { 'b' }
2361 * replacementChar = { 'a', 'a' }
2362 * result => { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }
2369 * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2370 * toBeReplaced = { 'c' }
2371 * replacementChar = { 'a' }
2372 * result => { 'a' , 'b', 'b', 'a', 'b', 'a' }
2380 * @param toBeReplaced
2381 * characters to be replaced
2383 * replacement characters
2384 * @return a new array of characters with substitutions or the given array
2386 * @exception NullPointerException
2387 * if the given array is null
2389 public static final char[] replace(char[] array, char[] toBeReplaced,
2390 char[] replacementChars) {
2392 int max = array.length;
2393 int replacedLength = toBeReplaced.length;
2394 int replacementLength = replacementChars.length;
2396 int[] starts = new int[5];
2397 int occurrenceCount = 0;
2399 if (!equals(toBeReplaced, replacementChars)) {
2401 next: for (int i = 0; i < max; i++) {
2403 while (j < replacedLength) {
2406 if (array[i + j] != toBeReplaced[j++])
2409 if (occurrenceCount == starts.length) {
2410 System.arraycopy(starts, 0,
2411 starts = new int[occurrenceCount * 2], 0,
2414 starts[occurrenceCount++] = i;
2417 if (occurrenceCount == 0)
2419 char[] result = new char[max + occurrenceCount
2420 * (replacementLength - replacedLength)];
2421 int inStart = 0, outStart = 0;
2422 for (int i = 0; i < occurrenceCount; i++) {
2423 int offset = starts[i] - inStart;
2424 System.arraycopy(array, inStart, result, outStart, offset);
2427 System.arraycopy(replacementChars, 0, result, outStart,
2429 inStart += replacedLength;
2430 outStart += replacementLength;
2432 System.arraycopy(array, inStart, result, outStart, max - inStart);
2437 * Return a new array which is the split of the given array using the given
2438 * divider and triming each subarray to remove whitespaces equals to ' '.
2447 * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2448 * result => { { 'a' }, { }, { 'a' }, { 'a' } }
2456 * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2457 * result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
2465 * array = { 'a' , ' ', 'b', 'b', 'a', 'b', 'a' }
2466 * result => { { 'a' }, { }, { 'a' }, { 'a' } }
2474 * array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' }
2475 * result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
2485 * @return a new array which is the split of the given array using the given
2486 * divider and triming each subarray to remove whitespaces equals to ' '
2488 public static final char[][] splitAndTrimOn(char divider, char[] array) {
2489 int length = array == null ? 0 : array.length;
2491 return NO_CHAR_CHAR;
2494 for (int i = 0; i < length; i++)
2495 if (array[i] == divider)
2497 char[][] split = new char[wordCount][];
2498 int last = 0, currentWord = 0;
2499 for (int i = 0; i < length; i++) {
2500 if (array[i] == divider) {
2501 int start = last, end = i - 1;
2502 while (start < i && array[start] == ' ')
2504 while (end > start && array[end] == ' ')
2506 split[currentWord] = new char[end - start + 1];
2507 System.arraycopy(array, start, split[currentWord++], 0, end
2512 int start = last, end = length - 1;
2513 while (start < length && array[start] == ' ')
2515 while (end > start && array[end] == ' ')
2517 split[currentWord] = new char[end - start + 1];
2519 .arraycopy(array, start, split[currentWord++], 0, end - start
2525 * Return a new array which is the split of the given array using the given
2534 * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2535 * result => { { 'a' }, { }, { 'a' }, { 'a' } }
2543 * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2544 * result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
2552 * array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' }
2553 * result => { { ' ', 'a', 'b', 'b', 'a', 'b', 'a', ' ' } }
2563 * @return a new array which is the split of the given array using the given
2566 public static final char[][] splitOn(char divider, char[] array) {
2567 int length = array == null ? 0 : array.length;
2569 return NO_CHAR_CHAR;
2572 for (int i = 0; i < length; i++)
2573 if (array[i] == divider)
2575 char[][] split = new char[wordCount][];
2576 int last = 0, currentWord = 0;
2577 for (int i = 0; i < length; i++) {
2578 if (array[i] == divider) {
2579 split[currentWord] = new char[i - last];
2581 .arraycopy(array, last, split[currentWord++], 0, i
2586 split[currentWord] = new char[length - last];
2587 System.arraycopy(array, last, split[currentWord], 0, length - last);
2592 * Return a new array which is the split of the given array using the given
2593 * divider. The given end is exclusive and the given start is inclusive.
2602 * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2605 * result => { { }, { }, { 'a' } }
2616 * the given starting index
2618 * the given ending index
2619 * @return a new array which is the split of the given array using the given
2621 * @exception ArrayIndexOutOfBoundsException
2622 * if start is lower than 0 or end is greater than the array
2625 public static final char[][] splitOn(char divider, char[] array, int start,
2627 int length = array == null ? 0 : array.length;
2628 if (length == 0 || start > end)
2629 return NO_CHAR_CHAR;
2632 for (int i = start; i < end; i++)
2633 if (array[i] == divider)
2635 char[][] split = new char[wordCount][];
2636 int last = start, currentWord = 0;
2637 for (int i = start; i < end; i++) {
2638 if (array[i] == divider) {
2639 split[currentWord] = new char[i - last];
2641 .arraycopy(array, last, split[currentWord++], 0, i
2646 split[currentWord] = new char[end - last];
2647 System.arraycopy(array, last, split[currentWord], 0, end - last);
2652 * Answers true if the given array starts with the given characters, false
2653 * otherwise. The comparison is case sensitive. <br>
2660 * toBeFound = { 'a' , 'b' }
2661 * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2669 * toBeFound = { 'a' , 'c' }
2670 * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2671 * result => false
2680 * the given character to search
2681 * @return true if the given array starts with the given characters, false
2683 * @exception NullPointerException
2684 * if the given array is null or if the given characters
2685 * array to be found is null
2687 public static final boolean startsWith(char[] array, char[] toBeFound) {
2688 int i = toBeFound.length;
2689 if (i > array.length)
2692 if (toBeFound[i] != array[i])
2698 * Answers a new array which is a copy of the given array starting at the
2699 * given start and ending at the given end. The given start is inclusive and
2700 * the given end is exclusive. Answers null if start is greater than end, if
2701 * start is lower than 0 or if end is greater than the length of the given
2702 * array. If end equals -1, it is converted to the array length. <br>
2709 * array = { { 'a' } , { 'b' } }
2712 * result => { { 'a' } }
2719 * array = { { 'a' } , { 'b' } }
2722 * result => { { 'a' }, { 'b' } }
2731 * the given starting index
2733 * the given ending index
2734 * @return a new array which is a copy of the given array starting at the
2735 * given start and ending at the given end
2736 * @exception NullPointerException
2737 * if the given array is null
2739 public static final char[][] subarray(char[][] array, int start, int end) {
2746 if (end > array.length)
2749 char[][] result = new char[end - start][];
2750 System.arraycopy(array, start, result, 0, end - start);
2755 * Answers a new array which is a copy of the given array starting at the
2756 * given start and ending at the given end. The given start is inclusive and
2757 * the given end is exclusive. Answers null if start is greater than end, if
2758 * start is lower than 0 or if end is greater than the length of the given
2759 * array. If end equals -1, it is converted to the array length. <br>
2766 * array = { 'a' , 'b' }
2769 * result => { 'a' }
2776 * array = { 'a', 'b' }
2779 * result => { 'a' , 'b' }
2788 * the given starting index
2790 * the given ending index
2791 * @return a new array which is a copy of the given array starting at the
2792 * given start and ending at the given end
2793 * @exception NullPointerException
2794 * if the given array is null
2796 public static final char[] subarray(char[] array, int start, int end) {
2803 if (end > array.length)
2806 char[] result = new char[end - start];
2807 System.arraycopy(array, start, result, 0, end - start);
2812 * Answers the result of a char[] conversion to lowercase. Answers null if
2813 * the given chars array is null. <br>
2814 * NOTE: if no conversion was necessary, then answers back the argument one.
2822 * chars = { 'a' , 'b' }
2823 * result => { 'a' , 'b' }
2830 * array = { 'A', 'b' }
2831 * result => { 'a' , 'b' }
2838 * the chars to convert
2839 * @return the result of a char[] conversion to lowercase
2841 final static public char[] toLowerCase(char[] chars) {
2844 int length = chars.length;
2845 char[] lowerChars = null;
2846 for (int i = 0; i < length; i++) {
2848 char lc = Character.toLowerCase(c);
2849 if ((c != lc) || (lowerChars != null)) {
2850 if (lowerChars == null) {
2851 System.arraycopy(chars, 0, lowerChars = new char[length],
2857 return lowerChars == null ? chars : lowerChars;
2861 * Answers a new array removing leading and trailing spaces (' '). Answers
2862 * the given array if there is no space characters to remove. <br>
2869 * chars = { ' ', 'a' , 'b', ' ', ' ' }
2870 * result => { 'a' , 'b' }
2877 * array = { 'A', 'b' }
2878 * result => { 'A' , 'b' }
2886 * @return a new array removing leading and trailing spaces (' ')
2888 final static public char[] trim(char[] chars) {
2893 int start = 0, length = chars.length, end = length - 1;
2894 while (start < length && chars[start] == ' ') {
2897 while (end > start && chars[end] == ' ') {
2900 if (start != 0 || end != length - 1) {
2901 return subarray(chars, start, end + 1);
2907 * Answers a string which is the concatenation of the given array using the
2908 * '.' as a separator. <br>
2915 * array = { { 'a' } , { 'b' } }
2916 * result => "a.b"
2923 * array = { { ' ', 'a' } , { 'b' } }
2924 * result => " a.b"
2932 * @return a string which is the concatenation of the given array using the
2933 * '.' as a separator
2935 final static public String toString(char[][] array) {
2936 char[] result = concatWith(array, '.');
2937 return new String(result);