| /******************************************************************************* |
| * Copyright (c) 2000, 2007 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| |
| *******************************************************************************/ |
| package org.eclipse.dltk.compiler; |
| |
| import org.eclipse.dltk.compiler.util.ScannerHelper; |
| |
| /** |
| * This class is a collection of helper methods to manipulate char arrays. |
| * |
| * |
| */ |
| public final class CharOperation { |
| |
| /** |
| * Constant for an empty char array |
| */ |
| public static final char[] NO_CHAR = new char[0]; |
| |
| /** |
| * Constant for an empty char array with two dimensions. |
| */ |
| public static final char[][] NO_CHAR_CHAR = new char[0][]; |
| |
| /** |
| * Constant for an empty String array. |
| * |
| * |
| */ |
| public static final String[] NO_STRINGS = new String[0]; |
| |
| private static final char MAX_OBVIOUS = 128; |
| |
| /** |
| * Answers a new array with appending the suffix character at the end of the |
| * array. <br> |
| * <br> |
| * For example:<br> |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a', 'b' } |
| * suffix = 'c' |
| * => result = { 'a', 'b' , 'c' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = null |
| * suffix = 'c' |
| * => result = { 'c' } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param array |
| * the array that is concanated with the suffix character |
| * @param suffix |
| * the suffix character |
| * @return the new array |
| */ |
| public static final char[] append(char[] array, char suffix) { |
| if (array == null) |
| return new char[] { suffix }; |
| int length = array.length; |
| System.arraycopy(array, 0, array = new char[length + 1], 0, length); |
| array[length] = suffix; |
| return array; |
| } |
| |
| /** |
| * Append the given subarray to the target array starting at the given index |
| * in the target array. The start of the subarray is inclusive, the end is |
| * exclusive. Answers a new target array if it needs to grow, otherwise |
| * answers the same target array. <br> |
| * For example:<br> |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * target = { 'a', 'b', '0' } |
| * index = 2 |
| * array = { 'c', 'd' } |
| * start = 0 |
| * end = 1 |
| * => result = { 'a', 'b' , 'c' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * target = { 'a', 'b' } |
| * index = 2 |
| * array = { 'c', 'd' } |
| * start = 0 |
| * end = 1 |
| * => result = { 'a', 'b' , 'c', '0', '0' , '0' } (new array) |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * target = { 'a', 'b', 'c' } |
| * index = 1 |
| * array = { 'c', 'd', 'e', 'f' } |
| * start = 1 |
| * end = 4 |
| * => result = { 'a', 'd' , 'e', 'f', '0', '0', '0', '0' } (new array) |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param target |
| * the given target |
| * @param index |
| * the given index |
| * @param array |
| * the given array |
| * @param start |
| * the given start index |
| * @param end |
| * the given end index |
| * |
| * @return the new array |
| * @throws NullPointerException |
| * if the target array is null |
| */ |
| public static final char[] append(char[] target, int index, char[] array, |
| int start, int end) { |
| int targetLength = target.length; |
| int subLength = end - start; |
| int newTargetLength = subLength + index; |
| if (newTargetLength > targetLength) { |
| System.arraycopy(target, 0, target = new char[newTargetLength * 2], |
| 0, index); |
| } |
| System.arraycopy(array, start, target, index, subLength); |
| return target; |
| } |
| |
| /** |
| * Answers the concatenation of the two arrays. It answers null if the two |
| * arrays are null. If the first array is null, then the second array is |
| * returned. If the second array is null, then the first array is returned. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * first = null |
| * second = null |
| * => result = null |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { { ' a' } } |
| * second = null |
| * => result = { { ' a' } } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = null |
| * second = { { ' a' } } |
| * => result = { { ' a' } } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { { ' b' } } |
| * second = { { ' a' } } |
| * => result = { { ' b' }, { ' a' } } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param first |
| * the first array to concatenate |
| * @param second |
| * the second array to concatenate |
| * @return the concatenation of the two arrays, or null if the two arrays |
| * are null. |
| */ |
| public static final char[][] arrayConcat(char[][] first, char[][] second) { |
| if (first == null) |
| return second; |
| if (second == null) |
| return first; |
| |
| int length1 = first.length; |
| int length2 = second.length; |
| char[][] result = new char[length1 + length2][]; |
| System.arraycopy(first, 0, result, 0, length1); |
| System.arraycopy(second, 0, result, length1, length2); |
| return result; |
| } |
| |
| /** |
| * Returns the char arrays as an array of Strings |
| * |
| * @param charArrays |
| * the char array to convert |
| * @return the char arrays as an array of Strings or null if the given char |
| * arrays is null. |
| * |
| */ |
| public static String[] charArrayToStringArray(char[][] charArrays) { |
| if (charArrays == null) |
| return null; |
| int length = charArrays.length; |
| if (length == 0) |
| return NO_STRINGS; |
| String[] strings = new String[length]; |
| for (int i = 0; i < length; i++) |
| strings[i] = new String(charArrays[i]); |
| return strings; |
| } |
| |
| /** |
| * Returns the char array as a String |
| * |
| * @param charArray |
| * the char array to convert |
| * @return the char array as a String or null if the given char array is |
| * null. |
| * |
| */ |
| public static String charToString(char[] charArray) { |
| if (charArray == null) |
| return null; |
| return new String(charArray); |
| } |
| |
| /** |
| * Returns the string as char array |
| * |
| * @param string |
| * the string to convert |
| * @return the char array or <code>null</code> |
| * @since 3.0 |
| */ |
| public static char[] stringToChar(String string) { |
| if (string == null) { |
| return null; |
| } |
| return string.toCharArray(); |
| } |
| |
| /** |
| * Answers a new array adding the second array at the end of first array. It |
| * answers null if the first and second are null. If the first array is |
| * null, then a new array char[][] is created with second. If the second |
| * array is null, then the first array is returned. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * first = null |
| * second = { 'a' } |
| * => result = { { ' a' } } |
| * </pre> |
| * |
| * <li> |
| * |
| * <pre> |
| * first = { { ' a' } } |
| * second = null |
| * => result = { { ' a' } } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { { ' a' } } |
| * second = { ' b' } |
| * => result = { { ' a' } , { ' b' } } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param first |
| * the first array to concatenate |
| * @param second |
| * the array to add at the end of the first array |
| * @return a new array adding the second array at the end of first array, or |
| * null if the two arrays are null. |
| */ |
| public static final char[][] arrayConcat(char[][] first, char[] second) { |
| if (second == null) |
| return first; |
| if (first == null) |
| return new char[][] { second }; |
| |
| int length = first.length; |
| char[][] result = new char[length + 1][]; |
| System.arraycopy(first, 0, result, 0, length); |
| result[length] = second; |
| return result; |
| } |
| |
| /** |
| * Compares the contents of the two arrays array and prefix. Returns |
| * <ul> |
| * <li>zero if the array starts with the prefix contents</li> |
| * <li>the difference between the first two characters that are not equal</li> |
| * <li>one if array length is lower than the prefix length and that the |
| * prefix starts with the array contents.</li> |
| * </ul> |
| * <p> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * array = null |
| * prefix = null |
| * => result = NullPointerException |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a', 'b', 'c', 'd', 'e' } |
| * prefix = { 'a', 'b', 'c'} |
| * => result = 0 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a', 'b', 'c', 'd', 'e' } |
| * prefix = { 'a', 'B', 'c'} |
| * => result = 32 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = { 'd', 'b', 'c', 'd', 'e' } |
| * prefix = { 'a', 'b', 'c'} |
| * => result = 3 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a', 'b', 'c', 'd', 'e' } |
| * prefix = { 'd', 'b', 'c'} |
| * => result = -3 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a', 'a', 'c', 'd', 'e' } |
| * prefix = { 'a', 'e', 'c'} |
| * => result = -4 |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * </p> |
| * |
| * @param array |
| * the given array |
| * @param prefix |
| * the given prefix |
| * @return the result of the comparison (>=0 if array>prefix) |
| * @throws NullPointerException |
| * if either array or prefix is null |
| */ |
| public static final int compareWith(char[] array, char[] prefix) { |
| int arrayLength = array.length; |
| int prefixLength = prefix.length; |
| int min = Math.min(arrayLength, prefixLength); |
| int i = 0; |
| while (min-- != 0) { |
| char c1 = array[i]; |
| char c2 = prefix[i++]; |
| if (c1 != c2) |
| return c1 - c2; |
| } |
| if (prefixLength == i) |
| return 0; |
| return -1; // array is shorter than prefix (e.g. array:'ab' < |
| // prefix:'abc'). |
| } |
| |
| /** |
| * Answers the concatenation of the two arrays. It answers null if the two |
| * arrays are null. If the first array is null, then the second array is |
| * returned. If the second array is null, then the first array is returned. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * first = null |
| * second = { 'a' } |
| * => result = { ' a' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { ' a' } |
| * second = null |
| * => result = { ' a' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { ' a' } |
| * second = { ' b' } |
| * => result = { ' a' , ' b' } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param first |
| * the first array to concatenate |
| * @param second |
| * the second array to concatenate |
| * @return the concatenation of the two arrays, or null if the two arrays |
| * are null. |
| */ |
| public static final char[] concat(char[] first, char[] second) { |
| if (first == null) |
| return second; |
| if (second == null) |
| return first; |
| |
| int length1 = first.length; |
| int length2 = second.length; |
| char[] result = new char[length1 + length2]; |
| System.arraycopy(first, 0, result, 0, length1); |
| System.arraycopy(second, 0, result, length1, length2); |
| return result; |
| } |
| |
| /** |
| * Answers the concatenation of the three arrays. It answers null if the |
| * three arrays are null. If first is null, it answers the concatenation of |
| * second and third. If second is null, it answers the concatenation of |
| * first and third. If third is null, it answers the concatenation of first |
| * and second. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * first = null |
| * second = { 'a' } |
| * third = { 'b' } |
| * => result = { ' a', 'b' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { 'a' } |
| * second = null |
| * third = { 'b' } |
| * => result = { ' a', 'b' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { 'a' } |
| * second = { 'b' } |
| * third = null |
| * => result = { ' a', 'b' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = null |
| * second = null |
| * third = null |
| * => result = null |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { 'a' } |
| * second = { 'b' } |
| * third = { 'c' } |
| * => result = { 'a', 'b', 'c' } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param first |
| * the first array to concatenate |
| * @param second |
| * the second array to concatenate |
| * @param third |
| * the third array to concatenate |
| * |
| * @return the concatenation of the three arrays, or null if the three |
| * arrays are null. |
| */ |
| public static final char[] concat(char[] first, char[] second, char[] third) { |
| if (first == null) |
| return concat(second, third); |
| if (second == null) |
| return concat(first, third); |
| if (third == null) |
| return concat(first, second); |
| |
| int length1 = first.length; |
| int length2 = second.length; |
| int length3 = third.length; |
| char[] result = new char[length1 + length2 + length3]; |
| System.arraycopy(first, 0, result, 0, length1); |
| System.arraycopy(second, 0, result, length1, length2); |
| System.arraycopy(third, 0, result, length1 + length2, length3); |
| return result; |
| } |
| |
| /** |
| * Answers the concatenation of the two arrays inserting the separator |
| * character between the two arrays. It answers null if the two arrays are |
| * null. If the first array is null, then the second array is returned. If |
| * the second array is null, then the first array is returned. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * first = null |
| * second = { 'a' } |
| * separator = '/' |
| * => result = { ' a' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { ' a' } |
| * second = null |
| * separator = '/' |
| * => result = { ' a' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { ' a' } |
| * second = { ' b' } |
| * separator = '/' |
| * => result = { ' a' , '/', 'b' } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param first |
| * the first array to concatenate |
| * @param second |
| * the second array to concatenate |
| * @param separator |
| * the character to insert |
| * @return the concatenation of the two arrays inserting the separator |
| * character between the two arrays , or null if the two arrays are |
| * null. |
| */ |
| public static final char[] concat(char[] first, char[] second, |
| char separator) { |
| if (first == null) |
| return second; |
| if (second == null) |
| return first; |
| |
| int length1 = first.length; |
| if (length1 == 0) |
| return second; |
| int length2 = second.length; |
| if (length2 == 0) |
| return first; |
| |
| char[] result = new char[length1 + length2 + 1]; |
| System.arraycopy(first, 0, result, 0, length1); |
| result[length1] = separator; |
| System.arraycopy(second, 0, result, length1 + 1, length2); |
| return result; |
| } |
| |
| public static final char[] concatWithSeparator(char[] first, char[] second, |
| char[] separator) { |
| if (first == null) |
| return second; |
| if (second == null) |
| return first; |
| |
| int length1 = first.length; |
| if (length1 == 0) |
| return second; |
| int length2 = second.length; |
| if (length2 == 0) |
| return first; |
| int length3 = separator.length; |
| |
| char[] result = new char[length1 + length2 + length3]; |
| System.arraycopy(first, 0, result, 0, length1); |
| System.arraycopy(separator, 0, result, length1, length3); |
| System.arraycopy(second, 0, result, length1 + length3, length2); |
| return result; |
| } |
| |
| /** |
| * Answers the concatenation of the three arrays inserting the sep1 |
| * character between the first two arrays and sep2 between the last two. It |
| * answers null if the three arrays are null. If the first array is null, |
| * then it answers the concatenation of second and third inserting the sep2 |
| * character between them. If the second array is null, then it answers the |
| * concatenation of first and third inserting the sep1 character between |
| * them. If the third array is null, then it answers the concatenation of |
| * first and second inserting the sep1 character between them. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * first = null |
| * sep1 = '/' |
| * second = { 'a' } |
| * sep2 = ':' |
| * third = { 'b' } |
| * => result = { ' a' , ':', 'b' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { 'a' } |
| * sep1 = '/' |
| * second = null |
| * sep2 = ':' |
| * third = { 'b' } |
| * => result = { ' a' , '/', 'b' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { 'a' } |
| * sep1 = '/' |
| * second = { 'b' } |
| * sep2 = ':' |
| * third = null |
| * => result = { ' a' , '/', 'b' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { 'a' } |
| * sep1 = '/' |
| * second = { 'b' } |
| * sep2 = ':' |
| * third = { 'c' } |
| * => result = { ' a' , '/', 'b' , ':', 'c' } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param first |
| * the first array to concatenate |
| * @param sep1 |
| * the character to insert |
| * @param second |
| * the second array to concatenate |
| * @param sep2 |
| * the character to insert |
| * @param third |
| * the second array to concatenate |
| * @return the concatenation of the three arrays inserting the sep1 |
| * character between the two arrays and sep2 between the last two. |
| */ |
| public static final char[] concat(char[] first, char sep1, char[] second, |
| char sep2, char[] third) { |
| if (first == null) |
| return concat(second, third, sep2); |
| if (second == null) |
| return concat(first, third, sep1); |
| if (third == null) |
| return concat(first, second, sep1); |
| |
| int length1 = first.length; |
| int length2 = second.length; |
| int length3 = third.length; |
| char[] result = new char[length1 + length2 + length3 + 2]; |
| System.arraycopy(first, 0, result, 0, length1); |
| result[length1] = sep1; |
| System.arraycopy(second, 0, result, length1 + 1, length2); |
| result[length1 + length2 + 1] = sep2; |
| System.arraycopy(third, 0, result, length1 + length2 + 2, length3); |
| return result; |
| } |
| |
| /** |
| * Answers a new array with prepending the prefix character and appending |
| * the suffix character at the end of the array. If array is null, it |
| * answers a new array containing the prefix and the suffix characters. <br> |
| * <br> |
| * For example:<br> |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * prefix = 'a' |
| * array = { 'b' } |
| * suffix = 'c' |
| * => result = { 'a', 'b' , 'c' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * prefix = 'a' |
| * array = null |
| * suffix = 'c' |
| * => result = { 'a', 'c' } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param prefix |
| * the prefix character |
| * @param array |
| * the array that is concanated with the prefix and suffix |
| * characters |
| * @param suffix |
| * the suffix character |
| * @return the new array |
| */ |
| public static final char[] concat(char prefix, char[] array, char suffix) { |
| if (array == null) |
| return new char[] { prefix, suffix }; |
| |
| int length = array.length; |
| char[] result = new char[length + 2]; |
| result[0] = prefix; |
| System.arraycopy(array, 0, result, 1, length); |
| result[length + 1] = suffix; |
| return result; |
| } |
| |
| /** |
| * Answers the concatenation of the given array parts using the given |
| * separator between each part and appending the given name at the end. <br> |
| * <br> |
| * For example:<br> |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * name = { 'c' } |
| * array = { { 'a' }, { 'b' } } |
| * separator = '.' |
| * => result = { 'a', '.', 'b' , '.', 'c' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * name = null |
| * array = { { 'a' }, { 'b' } } |
| * separator = '.' |
| * => result = { 'a', '.', 'b' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * name = { ' c' } |
| * array = null |
| * separator = '.' |
| * => result = { 'c' } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param name |
| * the given name |
| * @param array |
| * the given array |
| * @param separator |
| * the given separator |
| * @return the concatenation of the given array parts using the given |
| * separator between each part and appending the given name at the |
| * end |
| */ |
| public static final char[] concatWith(char[] name, char[][] array, |
| char separator) { |
| int nameLength = name == null ? 0 : name.length; |
| if (nameLength == 0) |
| return concatWith(array, separator); |
| |
| int length = array == null ? 0 : array.length; |
| if (length == 0) |
| return name; |
| |
| int size = nameLength; |
| int index = length; |
| while (--index >= 0) |
| if (array[index].length > 0) |
| size += array[index].length + 1; |
| char[] result = new char[size]; |
| index = size; |
| for (int i = length - 1; i >= 0; i--) { |
| int subLength = array[i].length; |
| if (subLength > 0) { |
| index -= subLength; |
| System.arraycopy(array[i], 0, result, index, subLength); |
| result[--index] = separator; |
| } |
| } |
| System.arraycopy(name, 0, result, 0, nameLength); |
| return result; |
| } |
| |
| /** |
| * Answers the concatenation of the given array parts using the given |
| * separator between each part and appending the given name at the end. <br> |
| * <br> |
| * For example:<br> |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * name = { 'c' } |
| * array = { { 'a' }, { 'b' } } |
| * separator = '.' |
| * => result = { 'a', '.', 'b' , '.', 'c' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * name = null |
| * array = { { 'a' }, { 'b' } } |
| * separator = '.' |
| * => result = { 'a', '.', 'b' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * name = { ' c' } |
| * array = null |
| * separator = '.' |
| * => result = { 'c' } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param array |
| * the given array |
| * @param name |
| * the given name |
| * @param separator |
| * the given separator |
| * @return the concatenation of the given array parts using the given |
| * separator between each part and appending the given name at the |
| * end |
| */ |
| public static final char[] concatWith(char[][] array, char[] name, |
| char separator) { |
| int nameLength = name == null ? 0 : name.length; |
| if (nameLength == 0) |
| return concatWith(array, separator); |
| |
| int length = array == null ? 0 : array.length; |
| if (length == 0) |
| return name; |
| |
| int size = nameLength; |
| int index = length; |
| while (--index >= 0) |
| if (array[index].length > 0) |
| size += array[index].length + 1; |
| char[] result = new char[size]; |
| index = 0; |
| for (int i = 0; i < length; i++) { |
| int subLength = array[i].length; |
| if (subLength > 0) { |
| System.arraycopy(array[i], 0, result, index, subLength); |
| index += subLength; |
| result[index++] = separator; |
| } |
| } |
| System.arraycopy(name, 0, result, index, nameLength); |
| return result; |
| } |
| |
| private static final int concatLength(char[][] array, int separatorLength) { |
| int size = 0; |
| if (array != null) { |
| int index = array.length; |
| if (index > 0) { |
| while (--index >= 0) { |
| if (array[index].length > 0) { |
| if (size != 0) { |
| size += separatorLength; |
| } |
| size += array[index].length; |
| } |
| } |
| } |
| } |
| return size; |
| } |
| |
| private static int concatWithTo(char[][] array, char separator, |
| char[] result, int index) { |
| int count = 0; |
| int arrayLen = array.length; |
| for (int i = 0; i < arrayLen; i++) { |
| int subLength = array[i].length; |
| if (subLength > 0) { |
| if (count != 0) { |
| result[index++] = separator; |
| } |
| ++count; |
| System.arraycopy(array[i], 0, result, index, subLength); |
| index += subLength; |
| } |
| } |
| return index; |
| } |
| |
| public static final char[] concatWith(char[][] first, char[][] second, |
| char separator) { |
| int firstLen = concatLength(first, 1); |
| if (firstLen == 0) { |
| return concatWith(second, separator); |
| } |
| int secondLen = concatLength(second, 1); |
| if (secondLen == 0) { |
| return concatWith(first, separator); |
| } |
| char[] result = new char[firstLen + 1 + secondLen]; |
| int index = 0; |
| index = concatWithTo(first, separator, result, index); |
| result[index++] = separator; |
| index = concatWithTo(second, separator, result, index); |
| return result; |
| } |
| |
| /** |
| * Answers the concatenation of the given array parts using the given |
| * separator between each part. <br> |
| * <br> |
| * For example:<br> |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * array = { { 'a' }, { 'b' } } |
| * separator = '.' |
| * => result = { 'a', '.', 'b' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = null |
| * separator = '.' |
| * => result = { } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param array |
| * the given array |
| * @param separator |
| * the given separator |
| * @return the concatenation of the given array parts using the given |
| * separator between each part |
| */ |
| public static final char[] concatWith(char[][] array, char separator) { |
| int length = array == null ? 0 : array.length; |
| if (length == 0) |
| return CharOperation.NO_CHAR; |
| |
| int size = length - 1; |
| int index = length; |
| while (--index >= 0) { |
| if (array[index].length == 0) |
| size--; |
| else |
| size += array[index].length; |
| } |
| if (size <= 0) |
| return CharOperation.NO_CHAR; |
| char[] result = new char[size]; |
| index = length; |
| while (--index >= 0) { |
| length = array[index].length; |
| if (length > 0) { |
| System.arraycopy(array[index], 0, result, (size -= length), |
| length); |
| if (--size >= 0) |
| result[size] = separator; |
| } |
| } |
| return result; |
| } |
| |
| public static final char[] concatWith(String[] array, char separator) { |
| int length = array == null ? 0 : array.length; |
| if (length == 0) |
| return CharOperation.NO_CHAR; |
| |
| int size = length - 1; |
| int index = length; |
| while (--index >= 0) { |
| final int len = array[index].length(); |
| if (len == 0) |
| size--; |
| else |
| size += len; |
| } |
| if (size <= 0) |
| return CharOperation.NO_CHAR; |
| char[] result = new char[size]; |
| index = length; |
| while (--index >= 0) { |
| length = array[index].length(); |
| if (length > 0) { |
| array[index].getChars(0, length, result, (size -= length)); |
| if (--size >= 0) |
| result[size] = separator; |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * @param array |
| * @param separator |
| * @return |
| * @since 3.0 |
| */ |
| public static final char[] concatWith(String[] array, String separator) { |
| int length = array == null ? 0 : array.length; |
| if (length == 0) |
| return CharOperation.NO_CHAR; |
| |
| int size = (length - 1) * separator.length(); |
| int index = length; |
| while (--index >= 0) { |
| final int len = array[index].length(); |
| if (len == 0) |
| size -= separator.length(); |
| else |
| size += len; |
| } |
| if (size <= 0) |
| return CharOperation.NO_CHAR; |
| char[] result = new char[size]; |
| index = length; |
| while (--index >= 0) { |
| length = array[index].length(); |
| if (length > 0) { |
| array[index].getChars(0, length, result, (size -= length)); |
| size -= separator.length(); |
| if (size >= 0) { |
| separator.getChars(0, separator.length(), result, size); |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Answers true if the array contains an occurrence of character, false |
| * otherwise. |
| * |
| * <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * character = 'c' |
| * array = { { ' a' }, { ' b' } } |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * character = 'a' |
| * array = { { ' a' }, { ' b' } } |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param character |
| * the character to search |
| * @param array |
| * the array in which the search is done |
| * @return true if the array contains an occurrence of character, false |
| * otherwise. |
| * @throws NullPointerException |
| * if array is null. |
| */ |
| public static final boolean contains(char character, char[][] array) { |
| for (int i = array.length; --i >= 0;) { |
| char[] subarray = array[i]; |
| for (int j = subarray.length; --j >= 0;) |
| if (subarray[j] == character) |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Answers true if the array contains an occurrence of character, false |
| * otherwise. |
| * |
| * <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * character = 'c' |
| * array = { ' b' } |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * character = 'a' |
| * array = { ' a' , ' b' } |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param character |
| * the character to search |
| * @param array |
| * the array in which the search is done |
| * @return true if the array contains an occurrence of character, false |
| * otherwise. |
| * @throws NullPointerException |
| * if array is null. |
| */ |
| public static final boolean contains(char character, char[] array) { |
| for (int i = array.length; --i >= 0;) |
| if (array[i] == character) |
| return true; |
| return false; |
| } |
| |
| /** |
| * Answers true if the array contains an occurrence of one of the |
| * characters, false otherwise. |
| * |
| * <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * characters = { 'c', 'd' } |
| * array = { 'a', ' b' } |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * characters = { 'c', 'd' } |
| * array = { 'a', ' b', 'c' } |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param characters |
| * the characters to search |
| * @param array |
| * the array in which the search is done |
| * @return true if the array contains an occurrence of one of the |
| * characters, false otherwise. |
| * @throws NullPointerException |
| * if array is null. |
| * |
| */ |
| public static final boolean contains(char[] characters, char[] array) { |
| for (int i = array.length; --i >= 0;) |
| for (int j = characters.length; --j >= 0;) |
| if (array[i] == characters[j]) |
| return true; |
| return false; |
| } |
| |
| /** |
| * Answers a deep copy of the toCopy array. |
| * |
| * @param toCopy |
| * the array to copy |
| * @return a deep copy of the toCopy array. |
| */ |
| |
| public static final char[][] deepCopy(char[][] toCopy) { |
| int toCopyLength = toCopy.length; |
| char[][] result = new char[toCopyLength][]; |
| for (int i = 0; i < toCopyLength; i++) { |
| char[] toElement = toCopy[i]; |
| int toElementLength = toElement.length; |
| char[] resultElement = new char[toElementLength]; |
| System.arraycopy(toElement, 0, resultElement, 0, toElementLength); |
| result[i] = resultElement; |
| } |
| return result; |
| } |
| |
| /** |
| * Return <code>true</code> if array starts with the sequence of characters |
| * contained in toBeFound, otherwise <code>false</code>. |
| * |
| * @param array |
| * @param toBeFound |
| * @return |
| */ |
| public static final boolean startsWith(char[] array, char[] toBeFound) { |
| int i = toBeFound.length; |
| if (array.length < i) |
| return false; |
| while (--i >= 0) |
| if (toBeFound[i] != array[i]) |
| return false; |
| return true; |
| } |
| |
| /** |
| * Return true if array ends with the sequence of characters contained in |
| * toBeFound, otherwise false. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a', 'b', 'c', 'd' } |
| * toBeFound = { 'b', 'c' } |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a', 'b', 'c' } |
| * toBeFound = { 'b', 'c' } |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param array |
| * the array to check |
| * @param toBeFound |
| * the array to find |
| * @return true if array ends with the sequence of characters contained in |
| * toBeFound, otherwise false. |
| * @throws NullPointerException |
| * if array is null or toBeFound is null |
| */ |
| public static final boolean endsWith(char[] array, char[] toBeFound) { |
| int i = toBeFound.length; |
| int j = array.length - i; |
| |
| if (j < 0) |
| return false; |
| while (--i >= 0) |
| if (toBeFound[i] != array[i + j]) |
| return false; |
| return true; |
| } |
| |
| /** |
| * Answers true if the two arrays are identical character by character, |
| * otherwise false. The equality is case sensitive. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * first = null |
| * second = null |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { { } } |
| * second = null |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { { 'a' } } |
| * second = { { 'a' } } |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { { 'A' } } |
| * second = { { 'a' } } |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param first |
| * the first array |
| * @param second |
| * the second array |
| * @return true if the two arrays are identical character by character, |
| * otherwise false |
| */ |
| public static final boolean equals(char[][] first, char[][] second) { |
| if (first == second) |
| return true; |
| if (first == null || second == null) |
| return false; |
| if (first.length != second.length) |
| return false; |
| |
| for (int i = first.length; --i >= 0;) |
| if (!equals(first[i], second[i])) |
| return false; |
| return true; |
| } |
| |
| /** |
| * Compares two strings null-safe. |
| * |
| * @param first |
| * @param second |
| * @return |
| */ |
| public static final boolean equals(String first, String second) { |
| if (first == second) |
| return true; |
| else if (first == null || second == null) |
| return false; |
| else |
| return first.equals(second); |
| } |
| |
| public static final boolean equals(String[] first, String[] second) { |
| if (first == second) |
| return true; |
| if (first == null || second == null) |
| return false; |
| if (first.length != second.length) |
| return false; |
| |
| for (int i = first.length; --i >= 0;) { |
| if (first[i] == null && second[i] != null) { |
| return false; |
| } |
| if (first[i] != null && second[i] == null) { |
| return false; |
| } |
| if (first[i] != null && !first[i].equals(second[i])) |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * If isCaseSensite is true, answers true if the two arrays are identical |
| * character by character, otherwise false. If it is false, answers true if |
| * the two arrays are identical character by character without checking the |
| * case, otherwise false. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * first = null |
| * second = null |
| * isCaseSensitive = true |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { { } } |
| * second = null |
| * isCaseSensitive = true |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { { 'A' } } |
| * second = { { 'a' } } |
| * isCaseSensitive = true |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { { 'A' } } |
| * second = { { 'a' } } |
| * isCaseSensitive = false |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param first |
| * the first array |
| * @param second |
| * the second array |
| * @param isCaseSensitive |
| * check whether or not the equality should be case sensitive |
| * @return true if the two arrays are identical character by character |
| * according to the value of isCaseSensitive, otherwise false |
| */ |
| public static final boolean equals(char[][] first, char[][] second, |
| boolean isCaseSensitive) { |
| |
| if (isCaseSensitive) { |
| return equals(first, second); |
| } |
| if (first == second) |
| return true; |
| if (first == null || second == null) |
| return false; |
| if (first.length != second.length) |
| return false; |
| |
| for (int i = first.length; --i >= 0;) |
| if (!equals(first[i], second[i], false)) |
| return false; |
| return true; |
| } |
| |
| /** |
| * Answers true if the two arrays are identical character by character, |
| * otherwise false. The equality is case sensitive. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * first = null |
| * second = null |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { } |
| * second = null |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { 'a' } |
| * second = { 'a' } |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { 'a' } |
| * second = { 'A' } |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param first |
| * the first array |
| * @param second |
| * the second array |
| * @return true if the two arrays are identical character by character, |
| * otherwise false |
| */ |
| public static final boolean equals(char[] first, char[] second) { |
| if (first == second) |
| return true; |
| if (first == null || second == null) |
| return false; |
| if (first.length != second.length) |
| return false; |
| |
| for (int i = first.length; --i >= 0;) |
| if (first[i] != second[i]) |
| return false; |
| return true; |
| } |
| |
| /** |
| * Answers true if the first array is identical character by character to a |
| * portion of the second array delimited from position secondStart |
| * (inclusive) to secondEnd(exclusive), otherwise false. The equality is |
| * case sensitive. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * first = null |
| * second = null |
| * secondStart = 0 |
| * secondEnd = 0 |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { } |
| * second = null |
| * secondStart = 0 |
| * secondEnd = 0 |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { 'a' } |
| * second = { 'a' } |
| * secondStart = 0 |
| * secondEnd = 1 |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { 'a' } |
| * second = { 'A' } |
| * secondStart = 0 |
| * secondEnd = 1 |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param first |
| * the first array |
| * @param second |
| * the second array |
| * @param secondStart |
| * inclusive start position in the second array to compare |
| * @param secondEnd |
| * exclusive end position in the second array to compare |
| * @return true if the first array is identical character by character to |
| * fragment of second array ranging from secondStart to secondEnd-1, |
| * otherwise false |
| * |
| */ |
| public static final boolean equals(char[] first, char[] second, |
| int secondStart, int secondEnd) { |
| if (first == second) |
| return true; |
| if (first == null || second == null) |
| return false; |
| if (first.length != secondEnd - secondStart) |
| return false; |
| |
| for (int i = first.length; --i >= 0;) |
| if (first[i] != second[i + secondStart]) |
| return false; |
| return true; |
| } |
| |
| /** |
| * If isCaseSensite is true, answers true if the two arrays are identical |
| * character by character, otherwise false. If it is false, answers true if |
| * the two arrays are identical character by character without checking the |
| * case, otherwise false. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * first = null |
| * second = null |
| * isCaseSensitive = true |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { } |
| * second = null |
| * isCaseSensitive = true |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { 'A' } |
| * second = { 'a' } |
| * isCaseSensitive = true |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * first = { 'A' } |
| * second = { 'a' } |
| * isCaseSensitive = false |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param first |
| * the first array |
| * @param second |
| * the second array |
| * @param isCaseSensitive |
| * check whether or not the equality should be case sensitive |
| * @return true if the two arrays are identical character by character |
| * according to the value of isCaseSensitive, otherwise false |
| */ |
| public static final boolean equals(char[] first, char[] second, |
| boolean isCaseSensitive) { |
| |
| if (isCaseSensitive) { |
| return equals(first, second); |
| } |
| if (first == second) |
| return true; |
| if (first == null || second == null) |
| return false; |
| if (first.length != second.length) |
| return false; |
| |
| for (int i = first.length; --i >= 0;) |
| if (Character.toLowerCase(first[i]) != Character |
| .toLowerCase(second[i])) |
| return false; |
| return true; |
| } |
| |
| /** |
| * If isCaseSensite is true, the equality is case sensitive, otherwise it is |
| * case insensitive. |
| * |
| * Answers true if the name contains the fragment at the starting index |
| * startIndex, otherwise false. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * fragment = { 'b', 'c' , 'd' } |
| * name = { 'a', 'b', 'c' , 'd' } |
| * startIndex = 1 |
| * isCaseSensitive = true |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * fragment = { 'b', 'c' , 'd' } |
| * name = { 'a', 'b', 'C' , 'd' } |
| * startIndex = 1 |
| * isCaseSensitive = true |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * fragment = { 'b', 'c' , 'd' } |
| * name = { 'a', 'b', 'C' , 'd' } |
| * startIndex = 0 |
| * isCaseSensitive = false |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * fragment = { 'b', 'c' , 'd' } |
| * name = { 'a', 'b'} |
| * startIndex = 0 |
| * isCaseSensitive = true |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param fragment |
| * the fragment to check |
| * @param name |
| * the array to check |
| * @param startIndex |
| * the starting index |
| * @param isCaseSensitive |
| * check whether or not the equality should be case sensitive |
| * @return true if the name contains the fragment at the starting index |
| * startIndex according to the value of isCaseSensitive, otherwise |
| * false. |
| * @throws NullPointerException |
| * if fragment or name is null. |
| */ |
| public static final boolean fragmentEquals(char[] fragment, char[] name, |
| int startIndex, boolean isCaseSensitive) { |
| |
| int max = fragment.length; |
| if (name.length < max + startIndex) |
| return false; |
| if (isCaseSensitive) { |
| for (int i = max; --i >= 0;) |
| // assumes the prefix is not larger than the name |
| if (fragment[i] != name[i + startIndex]) |
| return false; |
| return true; |
| } |
| for (int i = max; --i >= 0;) |
| // assumes the prefix is not larger than the name |
| if (Character.toLowerCase(fragment[i]) != Character |
| .toLowerCase(name[i + startIndex])) |
| return false; |
| return true; |
| } |
| |
| /** |
| * Answers a hashcode for the array |
| * |
| * @param array |
| * the array for which a hashcode is required |
| * @return the hashcode |
| * @throws NullPointerException |
| * if array is null |
| */ |
| public static final int hashCode(char[] array) { |
| int length = array.length; |
| int hash = length == 0 ? 31 : array[0]; |
| if (length < 8) { |
| for (int i = length; --i > 0;) |
| hash = (hash * 31) + array[i]; |
| } else { |
| // 8 characters is enough to compute a decent hash code, don't waste |
| // time examining every character |
| for (int i = length - 1, last = i > 16 ? i - 16 : 0; i > last; i -= 2) |
| hash = (hash * 31) + array[i]; |
| } |
| return hash & 0x7FFFFFFF; |
| } |
| |
| /** |
| * Answers true if c is a whitespace according to the JLS (\u000a, |
| * \u000c, \u000d, \u0009), otherwise false. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * c = ' ' |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * c = ' \u3000' |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param c |
| * the character to check |
| * @return true if c is a whitespace according to the JLS, otherwise false. |
| */ |
| public static boolean isWhitespace(char c) { |
| switch (c) { |
| case 10: /* \ u000a: LINE FEED */ |
| case 12: /* \ u000c: FORM FEED */ |
| case 13: /* \ u000d: CARRIAGE RETURN */ |
| case 32: /* \ u0020: SPACE */ |
| case 9: /* \ u0009: HORIZONTAL TABULATION */ |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| /** |
| * Answers the first index in the array for which the corresponding |
| * character is equal to toBeFound. Answers -1 if no occurrence of this |
| * character is found. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'c' |
| * array = { ' a', 'b', 'c', 'd' } |
| * result => 2 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'e' |
| * array = { ' a', 'b', 'c', 'd' } |
| * result => -1 |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param toBeFound |
| * the character to search |
| * @param array |
| * the array to be searched |
| * @return the first index in the array for which the corresponding |
| * character is equal to toBeFound, -1 otherwise |
| * @throws NullPointerException |
| * if array is null |
| */ |
| public static final int indexOf(char toBeFound, char[] array) { |
| return indexOf(toBeFound, array, 0); |
| } |
| |
| /** |
| * Answers the first index in the array for which the toBeFound array is a |
| * matching subarray following the case rule. Answers -1 if no match is |
| * found. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = { 'c' } |
| * array = { ' a', 'b', 'c', 'd' } |
| * result => 2 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = { 'e' } |
| * array = { ' a', 'b', 'c', 'd' } |
| * result => -1 |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param toBeFound |
| * the subarray to search |
| * @param array |
| * the array to be searched |
| * @param isCaseSensitive |
| * flag to know if the matching should be case sensitive |
| * @return the first index in the array for which the toBeFound array is a |
| * matching subarray following the case rule, -1 otherwise |
| * @throws NullPointerException |
| * if array is null or toBeFound is null |
| * |
| */ |
| public static final int indexOf(char[] toBeFound, char[] array, |
| boolean isCaseSensitive) { |
| return indexOf(toBeFound, array, isCaseSensitive, 0); |
| } |
| |
| /** |
| * Answers the first index in the array for which the toBeFound array is a |
| * matching subarray following the case rule starting at the index start. |
| * Answers -1 if no match is found. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = { 'c' } |
| * array = { ' a', 'b', 'c', 'd' } |
| * result => 2 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = { 'e' } |
| * array = { ' a', 'b', 'c', 'd' } |
| * result => -1 |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param toBeFound |
| * the subarray to search |
| * @param array |
| * the array to be searched |
| * @param isCaseSensitive |
| * flag to know if the matching should be case sensitive |
| * @param start |
| * the starting index |
| * @return the first index in the array for which the toBeFound array is a |
| * matching subarray following the case rule starting at the index |
| * start, -1 otherwise |
| * @throws NullPointerException |
| * if array is null or toBeFound is null |
| * |
| */ |
| public static final int indexOf(final char[] toBeFound, final char[] array, |
| final boolean isCaseSensitive, final int start) { |
| return indexOf(toBeFound, array, isCaseSensitive, start, array.length); |
| } |
| |
| /** |
| * Answers the first index in the array for which the toBeFound array is a |
| * matching subarray following the case rule starting at the index start. |
| * Answers -1 if no match is found. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = { 'c' } |
| * array = { ' a', 'b', 'c', 'd' } |
| * result => 2 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = { 'e' } |
| * array = { ' a', 'b', 'c', 'd' } |
| * result => -1 |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param toBeFound |
| * the subarray to search |
| * @param array |
| * the array to be searched |
| * @param isCaseSensitive |
| * flag to know if the matching should be case sensitive |
| * @param start |
| * the starting index (inclusive) |
| * @param end |
| * the end index (exclusive) |
| * @return the first index in the array for which the toBeFound array is a |
| * matching subarray following the case rule starting at the index |
| * start, -1 otherwise |
| * @throws NullPointerException |
| * if array is null or toBeFound is null |
| * |
| */ |
| public static final int indexOf(final char[] toBeFound, final char[] array, |
| final boolean isCaseSensitive, final int start, final int end) { |
| final int arrayLength = end; |
| final int toBeFoundLength = toBeFound.length; |
| if (toBeFoundLength > arrayLength) |
| return -1; |
| if (toBeFoundLength == 0) |
| return 0; |
| if (toBeFoundLength == arrayLength) { |
| if (isCaseSensitive) { |
| for (int i = start; i < arrayLength; i++) { |
| if (array[i] != toBeFound[i]) |
| return -1; |
| } |
| return 0; |
| } else { |
| for (int i = start; i < arrayLength; i++) { |
| if (Character.toLowerCase(array[i]) != Character |
| .toLowerCase(toBeFound[i])) |
| return -1; |
| } |
| return 0; |
| } |
| } |
| if (isCaseSensitive) { |
| arrayLoop: for (int i = start, max = arrayLength - toBeFoundLength |
| + 1; i < max; i++) { |
| if (array[i] == toBeFound[0]) { |
| for (int j = 1; j < toBeFoundLength; j++) { |
| if (array[i + j] != toBeFound[j]) |
| continue arrayLoop; |
| } |
| return i; |
| } |
| } |
| } else { |
| arrayLoop: for (int i = start, max = arrayLength - toBeFoundLength |
| + 1; i < max; i++) { |
| if (Character.toLowerCase(array[i]) == Character |
| .toLowerCase(toBeFound[0])) { |
| for (int j = 1; j < toBeFoundLength; j++) { |
| if (Character.toLowerCase(array[i + j]) != Character |
| .toLowerCase(toBeFound[j])) |
| continue arrayLoop; |
| } |
| return i; |
| } |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * Answers the first index in the array for which the corresponding |
| * character is equal to toBeFound starting the search at index start. |
| * Answers -1 if no occurrence of this character is found. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'c' |
| * array = { ' a', 'b', 'c', 'd' } |
| * start = 2 |
| * result => 2 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'c' |
| * array = { ' a', 'b', 'c', 'd' } |
| * start = 3 |
| * result => -1 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'e' |
| * array = { ' a', 'b', 'c', 'd' } |
| * start = 1 |
| * result => -1 |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param toBeFound |
| * the character to search |
| * @param array |
| * the array to be searched |
| * @param start |
| * the starting index |
| * @return the first index in the array for which the corresponding |
| * character is equal to toBeFound, -1 otherwise |
| * @throws NullPointerException |
| * if array is null |
| * @throws ArrayIndexOutOfBoundsException |
| * if start is lower than 0 |
| */ |
| public static final int indexOf(char toBeFound, char[] array, int start) { |
| for (int i = start; i < array.length; i++) |
| if (toBeFound == array[i]) |
| return i; |
| return -1; |
| } |
| |
| /** |
| * Answers the first index in the array for which the corresponding |
| * character is equal to toBeFound starting the search at index start and |
| * before the ending index. Answers -1 if no occurrence of this character is |
| * found. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'c' |
| * array = { ' a', 'b', 'c', 'd' } |
| * start = 2 |
| * result => 2 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'c' |
| * array = { ' a', 'b', 'c', 'd' } |
| * start = 3 |
| * result => -1 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'e' |
| * array = { ' a', 'b', 'c', 'd' } |
| * start = 1 |
| * result => -1 |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param toBeFound |
| * the character to search |
| * @param array |
| * the array to be searched |
| * @param start |
| * the starting index (inclusive) |
| * @param end |
| * the ending index (exclusive) |
| * @return the first index in the array for which the corresponding |
| * character is equal to toBeFound, -1 otherwise |
| * @throws NullPointerException |
| * if array is null |
| * @throws ArrayIndexOutOfBoundsException |
| * if start is lower than 0 or ending greater than array length |
| * |
| */ |
| public static final int indexOf(char toBeFound, char[] array, int start, |
| int end) { |
| for (int i = start; i < end; i++) |
| if (toBeFound == array[i]) |
| return i; |
| return -1; |
| } |
| |
| /** |
| * Answers the last index in the array for which the corresponding character |
| * is equal to toBeFound starting from the end of the array. Answers -1 if |
| * no occurrence of this character is found. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'c' |
| * array = { ' a', 'b', 'c', 'd' , 'c', 'e' } |
| * result => 4 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'e' |
| * array = { ' a', 'b', 'c', 'd' } |
| * result => -1 |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param toBeFound |
| * the character to search |
| * @param array |
| * the array to be searched |
| * @return the last index in the array for which the corresponding character |
| * is equal to toBeFound starting from the end of the array, -1 |
| * otherwise |
| * @throws NullPointerException |
| * if array is null |
| */ |
| public static final int lastIndexOf(char toBeFound, char[] array) { |
| for (int i = array.length; --i >= 0;) |
| if (toBeFound == array[i]) |
| return i; |
| return -1; |
| } |
| |
| /** |
| * Answers the last index in the array for which the corresponding character |
| * is equal to toBeFound stopping at the index startIndex. Answers -1 if no |
| * occurrence of this character is found. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'c' |
| * array = { ' a', 'b', 'c', 'd' } |
| * startIndex = 2 |
| * result => 2 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'c' |
| * array = { ' a', 'b', 'c', 'd', 'e' } |
| * startIndex = 3 |
| * result => -1 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'e' |
| * array = { ' a', 'b', 'c', 'd' } |
| * startIndex = 0 |
| * result => -1 |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param toBeFound |
| * the character to search |
| * @param array |
| * the array to be searched |
| * @param startIndex |
| * the stopping index |
| * @return the last index in the array for which the corresponding character |
| * is equal to toBeFound stopping at the index startIndex, -1 |
| * otherwise |
| * @throws NullPointerException |
| * if array is null |
| * @throws ArrayIndexOutOfBoundsException |
| * if startIndex is lower than 0 |
| */ |
| public static final int lastIndexOf(char toBeFound, char[] array, |
| int startIndex) { |
| for (int i = array.length; --i >= startIndex;) |
| if (toBeFound == array[i]) |
| return i; |
| return -1; |
| } |
| |
| /** |
| * Answers the last index in the array for which the corresponding character |
| * is equal to toBeFound starting from endIndex to startIndex. Answers -1 if |
| * no occurrence of this character is found. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'c' |
| * array = { ' a', 'b', 'c', 'd' } |
| * startIndex = 2 |
| * endIndex = 2 |
| * result => 2 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'c' |
| * array = { ' a', 'b', 'c', 'd', 'e' } |
| * startIndex = 3 |
| * endIndex = 4 |
| * result => -1 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'e' |
| * array = { ' a', 'b', 'c', 'd' } |
| * startIndex = 0 |
| * endIndex = 3 |
| * result => -1 |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param toBeFound |
| * the character to search |
| * @param array |
| * the array to be searched |
| * @param startIndex |
| * the stopping index |
| * @param endIndex |
| * the starting index |
| * @return the last index in the array for which the corresponding character |
| * is equal to toBeFound starting from endIndex to startIndex, -1 |
| * otherwise |
| * @throws NullPointerException |
| * if array is null |
| * @throws ArrayIndexOutOfBoundsException |
| * if endIndex is greater or equals to array length or starting |
| * is lower than 0 |
| */ |
| public static final int lastIndexOf(char toBeFound, char[] array, |
| int startIndex, int endIndex) { |
| for (int i = endIndex; --i >= startIndex;) |
| if (toBeFound == array[i]) |
| return i; |
| return -1; |
| } |
| |
| /** |
| * Answers the last portion of a name given a separator. <br> |
| * <br> |
| * For example, |
| * |
| * <pre> |
| * lastSegment("java.lang.Object".toCharArray(),'.') --> Object |
| * </pre> |
| * |
| * @param array |
| * the array |
| * @param separator |
| * the given separator |
| * @return the last portion of a name given a separator |
| * @throws NullPointerException |
| * if array is null |
| */ |
| final static public char[] lastSegment(char[] array, char separator) { |
| int pos = lastIndexOf(separator, array); |
| if (pos < 0) |
| return array; |
| return subarray(array, pos + 1, array.length); |
| } |
| |
| /** |
| * Answers true if the pattern matches the given name, false otherwise. This |
| * char[] pattern matching accepts wild-cards '*' and '?'. |
| * |
| * When not case sensitive, the pattern is assumed to already be lowercased, |
| * the name will be lowercased character per character as comparing. If name |
| * is null, the answer is false. If pattern is null, the answer is true if |
| * name is not null. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * pattern = { '?', 'b', '*' } |
| * name = { 'a', 'b', 'c' , 'd' } |
| * isCaseSensitive = true |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * pattern = { '?', 'b', '?' } |
| * name = { 'a', 'b', 'c' , 'd' } |
| * isCaseSensitive = true |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * pattern = { 'b', '*' } |
| * name = { 'a', 'b', 'c' , 'd' } |
| * isCaseSensitive = true |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param pattern |
| * the given pattern |
| * @param name |
| * the given name |
| * @param isCaseSensitive |
| * flag to know whether or not the matching should be case |
| * sensitive |
| * @return true if the pattern matches the given name, false otherwise |
| */ |
| public static final boolean match(char[] pattern, char[] name, |
| boolean isCaseSensitive) { |
| |
| if (name == null) |
| return false; // null name cannot match |
| if (pattern == null) |
| return true; // null pattern is equivalent to '*' |
| |
| return match(pattern, 0, pattern.length, name, 0, name.length, |
| isCaseSensitive); |
| } |
| |
| /** |
| * Answers true if a sub-pattern matches the subpart of the given name, |
| * false otherwise. char[] pattern matching, accepting wild-cards '*' and |
| * '?'. Can match only subset of name/pattern. end positions are |
| * non-inclusive. The subpattern is defined by the patternStart and |
| * pattternEnd positions. When not case sensitive, the pattern is assumed to |
| * already be lowercased, the name will be lowercased character per |
| * character as comparing. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * pattern = { '?', 'b', '*' } |
| * patternStart = 1 |
| * patternEnd = 3 |
| * name = { 'a', 'b', 'c' , 'd' } |
| * nameStart = 1 |
| * nameEnd = 4 |
| * isCaseSensitive = true |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * pattern = { '?', 'b', '*' } |
| * patternStart = 1 |
| * patternEnd = 2 |
| * name = { 'a', 'b', 'c' , 'd' } |
| * nameStart = 1 |
| * nameEnd = 2 |
| * isCaseSensitive = true |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param pattern |
| * the given pattern |
| * @param patternStart |
| * the given pattern start |
| * @param patternEnd |
| * the given pattern end |
| * @param name |
| * the given name |
| * @param nameStart |
| * the given name start |
| * @param nameEnd |
| * the given name end |
| * @param isCaseSensitive |
| * flag to know if the matching should be case sensitive |
| * @return true if a sub-pattern matches the subpart of the given name, |
| * false otherwise |
| */ |
| public static final boolean match(char[] pattern, int patternStart, |
| int patternEnd, char[] name, int nameStart, int nameEnd, |
| boolean isCaseSensitive) { |
| |
| if (name == null) |
| return false; // null name cannot match |
| if (pattern == null) |
| return true; // null pattern is equivalent to '*' |
| int iPattern = patternStart; |
| int iName = nameStart; |
| |
| if (patternEnd < 0) |
| patternEnd = pattern.length; |
| if (nameEnd < 0) |
| nameEnd = name.length; |
| |
| /* check first segment */ |
| char patternChar = 0; |
| while ((iPattern < patternEnd) |
| && (patternChar = pattern[iPattern]) != '*') { |
| if (iName == nameEnd) |
| return false; |
| if (patternChar != (isCaseSensitive ? name[iName] : Character |
| .toLowerCase(name[iName])) && patternChar != '?') { |
| return false; |
| } |
| iName++; |
| iPattern++; |
| } |
| /* check sequence of star+segment */ |
| int segmentStart; |
| if (patternChar == '*') { |
| segmentStart = ++iPattern; // skip star |
| } else { |
| segmentStart = 0; // force iName check |
| } |
| int prefixStart = iName; |
| checkSegment: while (iName < nameEnd) { |
| if (iPattern == patternEnd) { |
| iPattern = segmentStart; // mismatch - restart current |
| // segment |
| iName = ++prefixStart; |
| continue checkSegment; |
| } |
| /* segment is ending */ |
| if ((patternChar = pattern[iPattern]) == '*') { |
| segmentStart = ++iPattern; // skip start |
| if (segmentStart == patternEnd) { |
| return true; |
| } |
| prefixStart = iName; |
| continue checkSegment; |
| } |
| /* check current name character */ |
| if ((isCaseSensitive ? name[iName] : Character |
| .toLowerCase(name[iName])) != patternChar |
| && patternChar != '?') { |
| iPattern = segmentStart; // mismatch - restart current |
| // segment |
| iName = ++prefixStart; |
| continue checkSegment; |
| } |
| iName++; |
| iPattern++; |
| } |
| |
| return (segmentStart == patternEnd) |
| || (iName == nameEnd && iPattern == patternEnd) |
| || (iPattern == patternEnd - 1 && pattern[iPattern] == '*'); |
| } |
| |
| /** |
| * Answers true if the pattern matches the filepath using the pathSepatator, |
| * false otherwise. |
| * |
| * Path char[] pattern matching, accepting wild-cards '**', '*' and '?' |
| * (using Ant directory tasks conventions, also see |
| * "http://jakarta.apache.org/ant/manual/dirtasks.html#defaultexcludes"). |
| * Path pattern matching is enhancing regular pattern matching in supporting |
| * extra rule where '**' represent any folder combination. Special rule: - |
| * foo\ is equivalent to foo\** When not case sensitive, the pattern is |
| * assumed to already be lowercased, the name will be lowercased character |
| * per character as comparing. |
| * |
| * @param pattern |
| * the given pattern |
| * @param filepath |
| * the given path |
| * @param isCaseSensitive |
| * to find out whether or not the matching should be case |
| * sensitive |
| * @param pathSeparator |
| * the given path separator |
| * @return true if the pattern matches the filepath using the pathSepatator, |
| * false otherwise |
| */ |
| public static final boolean pathMatch(char[] pattern, char[] filepath, |
| boolean isCaseSensitive, char pathSeparator) { |
| |
| if (filepath == null) |
| return false; // null name cannot match |
| if (pattern == null) |
| return true; // null pattern is equivalent to '*' |
| |
| // offsets inside pattern |
| int pSegmentStart = pattern[0] == pathSeparator ? 1 : 0; |
| int pLength = pattern.length; |
| int pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, |
| pSegmentStart + 1); |
| if (pSegmentEnd < 0) |
| pSegmentEnd = pLength; |
| |
| // special case: pattern foo\ is equivalent to foo\** |
| boolean freeTrailingDoubleStar = pattern[pLength - 1] == pathSeparator; |
| |
| // offsets inside filepath |
| int fSegmentStart, fLength = filepath.length; |
| if (filepath[0] != pathSeparator) { |
| fSegmentStart = 0; |
| } else { |
| fSegmentStart = 1; |
| } |
| if (fSegmentStart != pSegmentStart) { |
| return false; // both must start with a separator or none. |
| } |
| int fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath, |
| fSegmentStart + 1); |
| if (fSegmentEnd < 0) |
| fSegmentEnd = fLength; |
| |
| // first segments |
| while (pSegmentStart < pLength |
| && !(pSegmentEnd == pLength && freeTrailingDoubleStar || (pSegmentEnd == pSegmentStart + 2 |
| && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*'))) { |
| |
| if (fSegmentStart >= fLength) |
| return false; |
| if (!CharOperation.match(pattern, pSegmentStart, pSegmentEnd, |
| filepath, fSegmentStart, fSegmentEnd, isCaseSensitive)) { |
| return false; |
| } |
| |
| // jump to next segment |
| pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, |
| pSegmentStart = pSegmentEnd + 1); |
| // skip separator |
| if (pSegmentEnd < 0) |
| pSegmentEnd = pLength; |
| |
| fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath, |
| fSegmentStart = fSegmentEnd + 1); |
| // skip separator |
| if (fSegmentEnd < 0) |
| fSegmentEnd = fLength; |
| } |
| |
| /* check sequence of doubleStar+segment */ |
| int pSegmentRestart; |
| if ((pSegmentStart >= pLength && freeTrailingDoubleStar) |
| || (pSegmentEnd == pSegmentStart + 2 |
| && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*')) { |
| pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, |
| pSegmentStart = pSegmentEnd + 1); |
| // skip separator |
| if (pSegmentEnd < 0) |
| pSegmentEnd = pLength; |
| pSegmentRestart = pSegmentStart; |
| } else { |
| if (pSegmentStart >= pLength) |
| return fSegmentStart >= fLength; // true if filepath is done |
| // too. |
| pSegmentRestart = 0; // force fSegmentStart check |
| } |
| int fSegmentRestart = fSegmentStart; |
| checkSegment: while (fSegmentStart < fLength) { |
| |
| if (pSegmentStart >= pLength) { |
| if (freeTrailingDoubleStar) |
| return true; |
| // mismatch - restart current path segment |
| pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, |
| pSegmentStart = pSegmentRestart); |
| if (pSegmentEnd < 0) |
| pSegmentEnd = pLength; |
| |
| fSegmentRestart = CharOperation.indexOf(pathSeparator, |
| filepath, fSegmentRestart + 1); |
| // skip separator |
| if (fSegmentRestart < 0) { |
| fSegmentRestart = fLength; |
| } else { |
| fSegmentRestart++; |
| } |
| fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath, |
| fSegmentStart = fSegmentRestart); |
| if (fSegmentEnd < 0) |
| fSegmentEnd = fLength; |
| continue checkSegment; |
| } |
| |
| /* path segment is ending */ |
| if (pSegmentEnd == pSegmentStart + 2 |
| && pattern[pSegmentStart] == '*' |
| && pattern[pSegmentStart + 1] == '*') { |
| pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, |
| pSegmentStart = pSegmentEnd + 1); |
| // skip separator |
| if (pSegmentEnd < 0) |
| pSegmentEnd = pLength; |
| pSegmentRestart = pSegmentStart; |
| fSegmentRestart = fSegmentStart; |
| if (pSegmentStart >= pLength) |
| return true; |
| continue checkSegment; |
| } |
| /* chech current path segment */ |
| if (!CharOperation.match(pattern, pSegmentStart, pSegmentEnd, |
| filepath, fSegmentStart, fSegmentEnd, isCaseSensitive)) { |
| // mismatch - restart current path segment |
| pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, |
| pSegmentStart = pSegmentRestart); |
| if (pSegmentEnd < 0) |
| pSegmentEnd = pLength; |
| |
| fSegmentRestart = CharOperation.indexOf(pathSeparator, |
| filepath, fSegmentRestart + 1); |
| // skip separator |
| if (fSegmentRestart < 0) { |
| fSegmentRestart = fLength; |
| } else { |
| fSegmentRestart++; |
| } |
| fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath, |
| fSegmentStart = fSegmentRestart); |
| if (fSegmentEnd < 0) |
| fSegmentEnd = fLength; |
| continue checkSegment; |
| } |
| // jump to next segment |
| pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, |
| pSegmentStart = pSegmentEnd + 1); |
| // skip separator |
| if (pSegmentEnd < 0) |
| pSegmentEnd = pLength; |
| |
| fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath, |
| fSegmentStart = fSegmentEnd + 1); |
| // skip separator |
| if (fSegmentEnd < 0) |
| fSegmentEnd = fLength; |
| } |
| |
| return (pSegmentRestart >= pSegmentEnd) |
| || (fSegmentStart >= fLength && pSegmentStart >= pLength) |
| || (pSegmentStart == pLength - 2 |
| && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*') |
| || (pSegmentStart == pLength && freeTrailingDoubleStar); |
| } |
| |
| /** |
| * Answers the number of occurrences of the given character in the given |
| * array, 0 if any. |
| * |
| * <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'b' |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * result => 3 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'c' |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * result => 0 |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param toBeFound |
| * the given character |
| * @param array |
| * the given array |
| * @return the number of occurrences of the given character in the given |
| * array, 0 if any |
| * @throws NullPointerException |
| * if array is null |
| */ |
| public static final int occurencesOf(char toBeFound, char[] array) { |
| int count = 0; |
| for (int i = 0; i < array.length; i++) |
| if (toBeFound == array[i]) |
| count++; |
| return count; |
| } |
| |
| /** |
| * Answers the number of occurrences of the given character in the given |
| * array starting at the given index, 0 if any. |
| * |
| * <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'b' |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * start = 2 |
| * result => 2 |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * toBeFound = 'c' |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * start = 0 |
| * result => 0 |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param toBeFound |
| * the given character |
| * @param array |
| * the given array |
| * @param start |
| * the given index |
| * @return the number of occurrences of the given character in the given |
| * array, 0 if any |
| * @throws NullPointerException |
| * if array is null |
| * @throws ArrayIndexOutOfBoundsException |
| * if start is lower than 0 |
| */ |
| public static final int occurencesOf(char toBeFound, char[] array, int start) { |
| int count = 0; |
| for (int i = start; i < array.length; i++) |
| if (toBeFound == array[i]) |
| count++; |
| return count; |
| } |
| |
| /** |
| * Answers true if the given name starts with the given prefix, false |
| * otherwise. The comparison is case sensitive. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * prefix = { 'a' , 'b' } |
| * name = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * prefix = { 'a' , 'c' } |
| * name = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param prefix |
| * the given prefix |
| * @param name |
| * the given name |
| * @return true if the given name starts with the given prefix, false |
| * otherwise |
| * @throws NullPointerException |
| * if the given name is null or if the given prefix is null |
| */ |
| public static final boolean prefixEquals(char[] prefix, char[] name) { |
| |
| int max = prefix.length; |
| if (name.length < max) |
| return false; |
| for (int i = max; --i >= 0;) |
| // assumes the prefix is not larger than the name |
| if (prefix[i] != name[i]) |
| return false; |
| return true; |
| } |
| |
| /** |
| * Answers true if the given name starts with the given prefix, false |
| * otherwise. isCaseSensitive is used to find out whether or not the |
| * comparison should be case sensitive. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * prefix = { 'a' , 'B' } |
| * name = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * isCaseSensitive = false |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * prefix = { 'a' , 'B' } |
| * name = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * isCaseSensitive = true |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param prefix |
| * the given prefix |
| * @param name |
| * the given name |
| * @param isCaseSensitive |
| * to find out whether or not the comparison should be case |
| * sensitive |
| * @return true if the given name starts with the given prefix, false |
| * otherwise |
| * @throws NullPointerException |
| * if the given name is null or if the given prefix is null |
| */ |
| public static final boolean prefixEquals(char[] prefix, char[] name, |
| boolean isCaseSensitive) { |
| |
| int max = prefix.length; |
| if (name.length < max) |
| return false; |
| if (isCaseSensitive) { |
| for (int i = max; --i >= 0;) |
| // assumes the prefix is not larger than the name |
| if (prefix[i] != name[i]) |
| return false; |
| return true; |
| } |
| |
| for (int i = max; --i >= 0;) |
| // assumes the prefix is not larger than the name |
| if (Character.toLowerCase(prefix[i]) != Character |
| .toLowerCase(name[i])) |
| return false; |
| return true; |
| } |
| |
| public static final boolean prefixEquals(char[] prefix, String name, |
| boolean isCaseSensitive) { |
| int max = prefix.length; |
| if (name.length() < max) |
| return false; |
| if (isCaseSensitive) { |
| for (int i = max; --i >= 0;) |
| // assumes the prefix is not larger than the name |
| if (prefix[i] != name.charAt(i)) |
| return false; |
| return true; |
| } |
| for (int i = max; --i >= 0;) |
| // assumes the prefix is not larger than the name |
| if (Character.toLowerCase(prefix[i]) != Character.toLowerCase(name |
| .charAt(i))) |
| return false; |
| return true; |
| } |
| |
| public static final boolean prefixEquals(String prefix, String name) { |
| return prefixEquals(prefix, name, false); |
| } |
| |
| public static final boolean prefixEquals(String prefix, String name, |
| boolean isCaseSensitive) { |
| int max = prefix.length(); |
| if (name.length() < max) |
| return false; |
| if (isCaseSensitive) { |
| for (int i = max; --i >= 0;) |
| // assumes the prefix is not larger than the name |
| if (prefix.charAt(i) != name.charAt(i)) |
| return false; |
| return true; |
| } |
| for (int i = max; --i >= 0;) |
| // assumes the prefix is not larger than the name |
| if (Character.toLowerCase(prefix.charAt(i)) != Character |
| .toLowerCase(name.charAt(i))) |
| return false; |
| return true; |
| } |
| |
| /** |
| * Replace all occurrence of the character to be replaced with the |
| * remplacement character in the given array. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * toBeReplaced = 'b' |
| * replacementChar = 'a' |
| * result => No returned value, but array is now equals to { 'a' , 'a', 'a', 'a', 'a', 'a' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * toBeReplaced = 'c' |
| * replacementChar = 'a' |
| * result => No returned value, but array is now equals to { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param array |
| * the given array |
| * @param toBeReplaced |
| * the character to be replaced |
| * @param replacementChar |
| * the replacement character |
| * @throws NullPointerException |
| * if the given array is null |
| */ |
| public static final void replace(char[] array, char toBeReplaced, |
| char replacementChar) { |
| if (toBeReplaced != replacementChar) { |
| for (int i = 0, max = array.length; i < max; i++) { |
| if (array[i] == toBeReplaced) |
| array[i] = replacementChar; |
| } |
| } |
| } |
| |
| /** |
| * Replace all occurrence of characters to be replaced with the remplacement |
| * character in the given array. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a' , 'b', 'b', 'c', 'a', 'b', 'c', 'a' } |
| * toBeReplaced = { 'b', 'c' } |
| * replacementChar = 'a' |
| * result => No returned value, but array is now equals to { 'a' , 'a', 'a', 'a', 'a', 'a', 'a', 'a' } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param array |
| * the given array |
| * @param toBeReplaced |
| * characters to be replaced |
| * @param replacementChar |
| * the replacement character |
| * @throws NullPointerException |
| * if arrays are null. |
| * |
| */ |
| public static final void replace(char[] array, char[] toBeReplaced, |
| char replacementChar) { |
| for (int i = array.length; --i >= 0;) |
| for (int j = toBeReplaced.length; --j >= 0;) |
| if (array[i] == toBeReplaced[j]) |
| array[i] = replacementChar; |
| } |
| |
| /** |
| * Answers a new array of characters with substitutions. No side-effect is |
| * operated on the original array, in case no substitution happened, then |
| * the result is the same as the original one. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * toBeReplaced = { 'b' } |
| * replacementChar = { 'a', 'a' } |
| * result => { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * toBeReplaced = { 'c' } |
| * replacementChar = { 'a' } |
| * result => { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param array |
| * the given array |
| * @param toBeReplaced |
| * characters to be replaced |
| * @param replacementChars |
| * the replacement characters |
| * @return a new array of characters with substitutions or the given array |
| * if none |
| * @throws NullPointerException |
| * if the given array is null |
| */ |
| public static final char[] replace(char[] array, char[] toBeReplaced, |
| char[] replacementChars) { |
| |
| int max = array.length; |
| int replacedLength = toBeReplaced.length; |
| int replacementLength = replacementChars.length; |
| |
| int[] starts = new int[5]; |
| int occurrenceCount = 0; |
| |
| if (!equals(toBeReplaced, replacementChars)) { |
| |
| next: for (int i = 0; i < max; i++) { |
| int j = 0; |
| while (j < replacedLength) { |
| if (i + j == max) |
| continue next; |
| if (array[i + j] != toBeReplaced[j++]) |
| continue next; |
| } |
| if (occurrenceCount == starts.length) { |
| System.arraycopy(starts, 0, |
| starts = new int[occurrenceCount * 2], 0, |
| occurrenceCount); |
| } |
| starts[occurrenceCount++] = i; |
| } |
| } |
| if (occurrenceCount == 0) |
| return array; |
| char[] result = new char[max + occurrenceCount |
| * (replacementLength - replacedLength)]; |
| int inStart = 0, outStart = 0; |
| for (int i = 0; i < occurrenceCount; i++) { |
| int offset = starts[i] - inStart; |
| System.arraycopy(array, inStart, result, outStart, offset); |
| inStart += offset; |
| outStart += offset; |
| System.arraycopy(replacementChars, 0, result, outStart, |
| replacementLength); |
| inStart += replacedLength; |
| outStart += replacementLength; |
| } |
| System.arraycopy(array, inStart, result, outStart, max - inStart); |
| return result; |
| } |
| |
| /** |
| * Replace all occurrence of the character to be replaced with the |
| * remplacement character in a copy of the given array. Returns the given |
| * array if no occurrences of the character to be replaced are found. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * toBeReplaced = 'b' |
| * replacementChar = 'a' |
| * result => A new array that is equals to { 'a' , 'a', 'a', 'a', 'a', 'a' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * toBeReplaced = 'c' |
| * replacementChar = 'a' |
| * result => The original array that remains unchanged. |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param array |
| * the given array |
| * @param toBeReplaced |
| * the character to be replaced |
| * @param replacementChar |
| * the replacement character |
| * @throws NullPointerException |
| * if the given array is null |
| * |
| */ |
| public static final char[] replaceOnCopy(char[] array, char toBeReplaced, |
| char replacementChar) { |
| |
| char[] result = null; |
| for (int i = 0, length = array.length; i < length; i++) { |
| char c = array[i]; |
| if (c == toBeReplaced) { |
| if (result == null) { |
| result = new char[length]; |
| System.arraycopy(array, 0, result, 0, i); |
| } |
| result[i] = replacementChar; |
| } else if (result != null) { |
| result[i] = c; |
| } |
| } |
| if (result == null) |
| return array; |
| return result; |
| } |
| |
| /** |
| * Return a new array which is the split of the given array using the given |
| * divider and triming each subarray to remove whitespaces equals to ' '. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * divider = 'b' |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * result => { { 'a' }, { }, { 'a' }, { 'a' } } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * divider = 'c' |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * result => { { 'a', 'b', 'b', 'a', 'b', 'a' } } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * divider = 'b' |
| * array = { 'a' , ' ', 'b', 'b', 'a', 'b', 'a' } |
| * result => { { 'a' }, { }, { 'a' }, { 'a' } } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * divider = 'c' |
| * array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' } |
| * result => { { 'a', 'b', 'b', 'a', 'b', 'a' } } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param divider |
| * the given divider |
| * @param array |
| * the given array |
| * @return a new array which is the split of the given array using the given |
| * divider and triming each subarray to remove whitespaces equals to |
| * ' ' |
| */ |
| public static final char[][] splitAndTrimOn(char divider, char[] array) { |
| int length = array == null ? 0 : array.length; |
| if (length == 0) |
| return NO_CHAR_CHAR; |
| |
| int wordCount = 1; |
| for (int i = 0; i < length; i++) |
| if (array[i] == divider) |
| wordCount++; |
| char[][] split = new char[wordCount][]; |
| int last = 0, currentWord = 0; |
| for (int i = 0; i < length; i++) { |
| if (array[i] == divider) { |
| int start = last, end = i - 1; |
| while (start < i && array[start] == ' ') |
| start++; |
| while (end > start && array[end] == ' ') |
| end--; |
| split[currentWord] = new char[end - start + 1]; |
| System.arraycopy(array, start, split[currentWord++], 0, end |
| - start + 1); |
| last = i + 1; |
| } |
| } |
| int start = last, end = length - 1; |
| while (start < length && array[start] == ' ') |
| start++; |
| while (end > start && array[end] == ' ') |
| end--; |
| split[currentWord] = new char[end - start + 1]; |
| System.arraycopy(array, start, split[currentWord++], 0, end - start + 1); |
| return split; |
| } |
| |
| /** |
| * Return a new array which is the split of the given array using the given |
| * divider. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * divider = 'b' |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * result => { { 'a' }, { }, { 'a' }, { 'a' } } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * divider = 'c' |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * result => { { 'a', 'b', 'b', 'a', 'b', 'a' } } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * divider = 'c' |
| * array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' } |
| * result => { { ' ', 'a', 'b', 'b', 'a', 'b', 'a', ' ' } } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param divider |
| * the given divider |
| * @param array |
| * the given array |
| * @return a new array which is the split of the given array using the given |
| * divider |
| */ |
| public static final char[][] splitOn(char divider, char[] array) { |
| int length = array == null ? 0 : array.length; |
| if (length == 0) |
| return NO_CHAR_CHAR; |
| |
| int wordCount = 1; |
| for (int i = 0; i < length; i++) |
| if (array[i] == divider) |
| wordCount++; |
| char[][] split = new char[wordCount][]; |
| int last = 0, currentWord = 0; |
| for (int i = 0; i < length; i++) { |
| if (array[i] == divider) { |
| split[currentWord] = new char[i - last]; |
| System.arraycopy(array, last, split[currentWord++], 0, i - last); |
| last = i + 1; |
| } |
| } |
| split[currentWord] = new char[length - last]; |
| System.arraycopy(array, last, split[currentWord], 0, length - last); |
| return split; |
| } |
| |
| /** |
| * Return a new array which is the split of the given array using the given |
| * divider. |
| * |
| * @param divider |
| * the given divider |
| * @param array |
| * the given array |
| * @return a new array which is the split of the given array using the given |
| * divider or <code>null</code> if {@code array} parameter is |
| * <code>null</code>. |
| */ |
| public static final char[][] splitOn(char[] divider, char[] array) { |
| if (array == null) { |
| return null; |
| } |
| int length = array.length; |
| if (length == 0) |
| return NO_CHAR_CHAR; |
| |
| int wordCount = 1; |
| { |
| int i = 0; |
| while (i + divider.length <= length) { |
| i = indexOf(divider, array, false, i); |
| if (i == -1) { |
| break; |
| } |
| ++wordCount; |
| i += divider.length; |
| } |
| } |
| char[][] split = new char[wordCount][]; |
| int last = 0, currentWord = 0; |
| int i = 0; |
| while (i + divider.length <= length) { |
| i = indexOf(divider, array, false, i); |
| if (i == -1) { |
| break; |
| } |
| split[currentWord] = new char[i - last]; |
| System.arraycopy(array, last, split[currentWord++], 0, i - last); |
| i += divider.length; |
| last = i; |
| } |
| split[currentWord] = new char[length - last]; |
| System.arraycopy(array, last, split[currentWord], 0, length - last); |
| return split; |
| } |
| |
| /** |
| * Return a new array which is the split of the given array using the given |
| * divider. The given end is exclusive and the given start is inclusive. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * divider = 'b' |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * start = 2 |
| * end = 5 |
| * result => { { }, { 'a' }, { } } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param divider |
| * the given divider |
| * @param array |
| * the given array |
| * @param start |
| * the given starting index |
| * @param end |
| * the given ending index |
| * @return a new array which is the split of the given array using the given |
| * divider |
| * @throws ArrayIndexOutOfBoundsException |
| * if start is lower than 0 or end is greater than the array |
| * length |
| */ |
| public static final char[][] splitOn(char divider, char[] array, int start, |
| int end) { |
| int length = array == null ? 0 : array.length; |
| if (length == 0 || start > end) |
| return NO_CHAR_CHAR; |
| |
| int wordCount = 1; |
| for (int i = start; i < end; i++) |
| if (array[i] == divider) |
| wordCount++; |
| char[][] split = new char[wordCount][]; |
| int last = start, currentWord = 0; |
| for (int i = start; i < end; i++) { |
| if (array[i] == divider) { |
| split[currentWord] = new char[i - last]; |
| System.arraycopy(array, last, split[currentWord++], 0, i - last); |
| last = i + 1; |
| } |
| } |
| split[currentWord] = new char[end - last]; |
| System.arraycopy(array, last, split[currentWord], 0, end - last); |
| return split; |
| } |
| |
| /** |
| * Answers a new array which is a copy of the given array starting at the |
| * given start and ending at the given end. The given start is inclusive and |
| * the given end is exclusive. Answers null if start is greater than end, if |
| * start is lower than 0 or if end is greater than the length of the given |
| * array. If end equals -1, it is converted to the array length. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * array = { { 'a' } , { 'b' } } |
| * start = 0 |
| * end = 1 |
| * result => { { 'a' } } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = { { 'a' } , { 'b' } } |
| * start = 0 |
| * end = -1 |
| * result => { { 'a' }, { 'b' } } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param array |
| * the given array |
| * @param start |
| * the given starting index |
| * @param end |
| * the given ending index |
| * @return a new array which is a copy of the given array starting at the |
| * given start and ending at the given end |
| * @throws NullPointerException |
| * if the given array is null |
| */ |
| public static final char[][] subarray(char[][] array, int start, int end) { |
| if (end == -1) |
| end = array.length; |
| if (start > end) |
| return null; |
| if (start < 0) |
| return null; |
| if (end > array.length) |
| return null; |
| |
| char[][] result = new char[end - start][]; |
| System.arraycopy(array, start, result, 0, end - start); |
| return result; |
| } |
| |
| /** |
| * Answers a new array which is a copy of the given array starting at the |
| * given start and ending at the given end. The given start is inclusive and |
| * the given end is exclusive. Answers null if start is greater than end, if |
| * start is lower than 0 or if end is greater than the length of the given |
| * array. If end equals -1, it is converted to the array length. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a' , 'b' } |
| * start = 0 |
| * end = 1 |
| * result => { 'a' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a', 'b' } |
| * start = 0 |
| * end = -1 |
| * result => { 'a' , 'b' } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param array |
| * the given array |
| * @param start |
| * the given starting index |
| * @param end |
| * the given ending index |
| * @return a new array which is a copy of the given array starting at the |
| * given start and ending at the given end |
| * @throws NullPointerException |
| * if the given array is null |
| */ |
| public static final char[] subarray(char[] array, int start, int end) { |
| if (end == -1) |
| end = array.length; |
| if (start > end) |
| return null; |
| if (start < 0) |
| return null; |
| if (end > array.length) |
| return null; |
| |
| char[] result = new char[end - start]; |
| System.arraycopy(array, start, result, 0, end - start); |
| return result; |
| } |
| |
| /** |
| * Answers the result of a char[] conversion to lowercase. Answers null if |
| * the given chars array is null. <br> |
| * NOTE: If no conversion was necessary, then answers back the argument one. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * chars = { 'a' , 'b' } |
| * result => { 'a' , 'b' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = { 'A', 'b' } |
| * result => { 'a' , 'b' } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param chars |
| * the chars to convert |
| * @return the result of a char[] conversion to lowercase |
| */ |
| final static public char[] toLowerCase(char[] chars) { |
| if (chars == null) |
| return null; |
| int length = chars.length; |
| char[] lowerChars = null; |
| for (int i = 0; i < length; i++) { |
| char c = chars[i]; |
| char lc = Character.toLowerCase(c); |
| if ((c != lc) || (lowerChars != null)) { |
| if (lowerChars == null) { |
| System.arraycopy(chars, 0, lowerChars = new char[length], |
| 0, i); |
| } |
| lowerChars[i] = lc; |
| } |
| } |
| return lowerChars == null ? chars : lowerChars; |
| } |
| |
| public static char[][] toLowerCase(char[][] names) { |
| int length = names.length; |
| char[][] result = new char[length][]; |
| for (int i = 0; i < length; i++) |
| result[i] = toLowerCase(names[i]); |
| return result; |
| } |
| |
| /** |
| * Answers a new array removing leading and trailing spaces (' '). Answers |
| * the given array if there is no space characters to remove. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * chars = { ' ', 'a' , 'b', ' ', ' ' } |
| * result => { 'a' , 'b' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = { 'A', 'b' } |
| * result => { 'A' , 'b' } |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param chars |
| * the given array |
| * @return a new array removing leading and trailing spaces (' ') |
| */ |
| final static public char[] trim(char[] chars) { |
| |
| if (chars == null) |
| return null; |
| |
| int start = 0, length = chars.length, end = length - 1; |
| while (start < length && chars[start] == ' ') { |
| start++; |
| } |
| while (end > start && chars[end] == ' ') { |
| end--; |
| } |
| if (start != 0 || end != length - 1) { |
| return subarray(chars, start, end + 1); |
| } |
| return chars; |
| } |
| |
| /** |
| * Answers a string which is the concatenation of the given array using the |
| * '.' as a separator. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * array = { { 'a' } , { 'b' } } |
| * result => "a.b" |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = { { ' ', 'a' } , { 'b' } } |
| * result => " a.b" |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param array |
| * the given array |
| * @return a string which is the concatenation of the given array using the |
| * '.' as a separator |
| */ |
| final static public String toString(char[][] array) { |
| char[] result = concatWith(array, '.'); |
| return new String(result); |
| } |
| |
| /** |
| * Answers an array of strings from the given array of char array. |
| * |
| * @param array |
| * the given array |
| * @return an array of strings |
| * |
| */ |
| final static public String[] toStrings(char[][] array) { |
| if (array == null) |
| return NO_STRINGS; |
| int length = array.length; |
| if (length == 0) |
| return NO_STRINGS; |
| String[] result = new String[length]; |
| for (int i = 0; i < length; i++) |
| result[i] = new String(array[i]); |
| return result; |
| } |
| |
| /** |
| * Answers true if the pattern matches the given name using CamelCase rules, |
| * or false otherwise. char[] CamelCase matching does NOT accept explicit |
| * wild-cards '*' and '?' and is inherently case sensitive. <br> |
| * CamelCase denotes the convention of writing compound names without |
| * spaces, and capitalizing every term. This function recognizes both upper |
| * and lower CamelCase, depending whether the leading character is |
| * capitalized or not. The leading part of an upper CamelCase pattern is |
| * assumed to contain a sequence of capitals which are appearing in the |
| * matching name; e.g. 'NPE' will match 'NullPointerException', but not |
| * 'NewPerfData'. A lower CamelCase pattern uses a lowercase first |
| * character. In Script, type names follow the upper CamelCase convention, |
| * whereas method or field names follow the lower CamelCase convention. <br> |
| * The pattern may contain lowercase characters, which will be match in a |
| * case sensitive way. These characters must appear in sequence in the name. |
| * For instance, 'NPExcep' will match 'NullPointerException', but not |
| * 'NullPointerExCEPTION' or 'NuPoEx' will match 'NullPointerException', but |
| * not 'NoPointerException'. <br> |
| * <br> |
| * Examples: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * pattern = { 'N', 'P', 'E' } |
| * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' } |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * pattern = { 'N', 'P', 'E' } |
| * name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' } |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * pattern = { 'N', 'u', 'P', 'o', 'E', 'x' } |
| * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' } |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * pattern = { 'N', 'u', 'P', 'o', 'E', 'x' } |
| * name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' } |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * pattern = { 'n', p', 'e' } |
| * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' } |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param pattern |
| * the given pattern |
| * @param name |
| * the given name |
| * @return true if the pattern matches the given name, false otherwise |
| * |
| */ |
| public static final boolean camelCaseMatch(char[] pattern, char[] name) { |
| if (pattern == null) |
| return true; // null pattern is equivalent to '*' |
| if (name == null) |
| return false; // null name cannot match |
| |
| return camelCaseMatch(pattern, 0, pattern.length, name, 0, name.length); |
| } |
| |
| /** |
| * Answers true if a sub-pattern matches the subpart of the given name using |
| * CamelCase rules, or false otherwise. char[] CamelCase matching does NOT |
| * accept explicit wild-cards '*' and '?' and is inherently case sensitive. |
| * Can match only subset of name/pattern, considering end positions as |
| * non-inclusive. The subpattern is defined by the patternStart and |
| * patternEnd positions. <br> |
| * CamelCase denotes the convention of writing compound names without |
| * spaces, and capitalizing every term. This function recognizes both upper |
| * and lower CamelCase, depending whether the leading character is |
| * capitalized or not. The leading part of an upper CamelCase pattern is |
| * assumed to contain a sequence of capitals which are appearing in the |
| * matching name; e.g. 'NPE' will match 'NullPointerException', but not |
| * 'NewPerfData'. A lower CamelCase pattern uses a lowercase first |
| * character. In Script, type names follow the upper CamelCase convention, |
| * whereas method or field names follow the lower CamelCase convention. <br> |
| * The pattern may contain lowercase characters, which will be match in a |
| * case sensitive way. These characters must appear in sequence in the name. |
| * For instance, 'NPExcep' will match 'NullPointerException', but not |
| * 'NullPointerExCEPTION' or 'NuPoEx' will match 'NullPointerException', but |
| * not 'NoPointerException'. <br> |
| * <br> |
| * Examples: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * pattern = { 'N', 'P', 'E' } |
| * patternStart = 0 |
| * patternEnd = 3 |
| * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' } |
| * nameStart = 0 |
| * nameEnd = 20 |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * pattern = { 'N', 'P', 'E' } |
| * patternStart = 0 |
| * patternEnd = 3 |
| * name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' } |
| * nameStart = 0 |
| * nameEnd = 21 |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * pattern = { 'N', 'u', 'P', 'o', 'E', 'x' } |
| * patternStart = 0 |
| * patternEnd = 6 |
| * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' } |
| * nameStart = 0 |
| * nameEnd = 20 |
| * result => true |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * pattern = { 'N', 'u', 'P', 'o', 'E', 'x' } |
| * patternStart = 0 |
| * patternEnd = 6 |
| * name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' } |
| * nameStart = 0 |
| * nameEnd = 21 |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * pattern = { 'n', p', 'e' } |
| * patternStart = 0 |
| * patternEnd = 3 |
| * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' } |
| * nameStart = 0 |
| * nameEnd = 20 |
| * result => false |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param pattern |
| * the given pattern |
| * @param patternStart |
| * the start index of the pattern, inclusive |
| * @param patternEnd |
| * the end index of the pattern, exclusive |
| * @param name |
| * the given name |
| * @param nameStart |
| * the start index of the name, inclusive |
| * @param nameEnd |
| * the end index of the name, exclusive |
| * @return true if a sub-pattern matches the subpart of the given name, |
| * false otherwise |
| * |
| */ |
| public static final boolean camelCaseMatch(char[] pattern, |
| int patternStart, int patternEnd, char[] name, int nameStart, |
| int nameEnd) { |
| if (name == null) |
| return false; // null name cannot match |
| if (pattern == null) |
| return true; // null pattern is equivalent to '*' |
| if (patternEnd < 0) |
| patternEnd = pattern.length; |
| if (nameEnd < 0) |
| nameEnd = name.length; |
| |
| if (patternEnd <= patternStart) |
| return nameEnd <= nameStart; |
| if (nameEnd <= nameStart) |
| return false; |
| // check first pattern char |
| if (name[nameStart] != pattern[patternStart]) { |
| // first char must strictly match (upper/lower) |
| return false; |
| } |
| |
| char patternChar, nameChar; |
| int iPattern = patternStart; |
| int iName = nameStart; |
| |
| // Main loop is on pattern characters |
| while (true) { |
| |
| iPattern++; |
| iName++; |
| |
| if (iPattern == patternEnd) { |
| // We have exhausted pattern, so it's a match |
| return true; |
| } |
| |
| if (iName == nameEnd) { |
| // We have exhausted name (and not pattern), so it's not a match |
| return false; |
| } |
| |
| // For as long as we're exactly matching, bring it on (even if it's |
| // a lower case character) |
| if ((patternChar = pattern[iPattern]) == name[iName]) { |
| continue; |
| } |
| |
| // If characters are not equals, then it's not a match if |
| // patternChar is lowercase |
| if (patternChar < MAX_OBVIOUS) { |
| if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[patternChar] & ScannerHelper.C_UPPER_LETTER) == 0) { |
| return false; |
| } |
| } else if (Character.isJavaIdentifierPart(patternChar) |
| && !Character.isUpperCase(patternChar)) { |
| return false; |
| } |
| |
| // patternChar is uppercase, so let's find the next uppercase in |
| // name |
| while (true) { |
| if (iName == nameEnd) { |
| // We have exhausted name (and not pattern), so it's not a |
| // match |
| return false; |
| } |
| |
| nameChar = name[iName]; |
| if (nameChar < MAX_OBVIOUS) { |
| if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[nameChar] & (ScannerHelper.C_LOWER_LETTER |
| | ScannerHelper.C_SPECIAL | ScannerHelper.C_DIGIT)) != 0) { |
| // nameChar is lowercase |
| iName++; |
| // nameChar is uppercase... |
| } else if (patternChar != nameChar) { |
| // .. and it does not match patternChar, so it's not a |
| // match |
| return false; |
| } else { |
| // .. and it matched patternChar. Back to the big loop |
| break; |
| } |
| } else if (Character.isJavaIdentifierPart(nameChar) |
| && !Character.isUpperCase(nameChar)) { |
| // nameChar is lowercase |
| iName++; |
| // nameChar is uppercase... |
| } else if (patternChar != nameChar) { |
| // .. and it does not match patternChar, so it's not a match |
| return false; |
| } else { |
| // .. and it matched patternChar. Back to the big loop |
| break; |
| } |
| } |
| // At this point, either name has been exhausted, or it is at an |
| // uppercase letter. |
| // Since pattern is also at an uppercase letter |
| } |
| } |
| |
| /** |
| * Answers true if the characters of the pattern are contained in the name |
| * as a substring, in a case-insensitive way. |
| * |
| * @param pattern |
| * the given pattern |
| * @param name |
| * the given name |
| * @return true if the pattern matches the given name, false otherwise |
| * @since 3.12 |
| */ |
| public static final boolean substringMatch(String pattern, String name) { |
| if (pattern == null || pattern.length() == 0) { |
| return true; |
| } |
| if (name == null) { |
| return false; |
| } |
| return checkSubstringMatch(pattern.toCharArray(), name.toCharArray()); |
| } |
| |
| /** |
| * Answers true if the characters of the pattern are contained in the name |
| * as a substring, in a case-insensitive way. |
| * |
| * @param pattern |
| * the given pattern |
| * @param name |
| * the given name |
| * @return true if the pattern matches the given name, false otherwise |
| * @since 3.12 |
| */ |
| public static final boolean substringMatch(char[] pattern, char[] name) { |
| if (pattern == null || pattern.length == 0) { |
| return true; |
| } |
| if (name == null) { |
| return false; |
| } |
| return checkSubstringMatch(pattern, name); |
| } |
| |
| /** |
| * Internal substring matching method; called after the null and length |
| * checks are performed. |
| * |
| * @param pattern |
| * the given pattern |
| * @param name |
| * the given name |
| * @return true if the pattern matches the given name, false otherwise |
| * |
| * @see CharOperation#substringMatch(char[], char[]) |
| */ |
| private static final boolean checkSubstringMatch(char[] pattern, |
| char[] name) { |
| |
| /* |
| * XXX: to be revised/enabled |
| * |
| * // allow non-consecutive occurrence of pattern characters if |
| * (pattern.length >= 3) { int pidx = 0; |
| * |
| * for (int nidx = 0; nidx < name.length; nidx++) { if |
| * (Character.toLowerCase(name[nidx]) == |
| * Character.toLowerCase(pattern[pidx])) pidx++; if (pidx == |
| * pattern.length) return true; } |
| * |
| * // for short patterns only allow consecutive occurrence } else { |
| */ |
| // outer loop iterates on the characters of the name; trying to |
| // match at any possible position |
| outer: for (int nidx = 0; nidx < name.length - pattern.length |
| + 1; nidx++) { |
| // inner loop iterates on pattern characters |
| for (int pidx = 0; pidx < pattern.length; pidx++) { |
| if (Character.toLowerCase(name[nidx + pidx]) != Character |
| .toLowerCase(pattern[pidx])) { |
| // no match until parameter list; do not match parameter |
| // list |
| if ((name[nidx + pidx] == '(') |
| || (name[nidx + pidx] == ':')) |
| return false; |
| continue outer; |
| } |
| if (pidx == pattern.length - 1) |
| return true; |
| } |
| } |
| // XXX: } |
| |
| return false; |
| } |
| |
| /** |
| * Answers a new array removing a given character. Answers the given array |
| * if there is no occurence of the character to remove. <br> |
| * <br> |
| * For example: |
| * <ol> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a' , 'b', 'b', 'c', 'b', 'a' } |
| * toBeRemoved = 'b' |
| * return { 'a' , 'c', 'a' } |
| * </pre> |
| * |
| * </li> |
| * <li> |
| * |
| * <pre> |
| * array = { 'a' , 'b', 'b', 'a', 'b', 'a' } |
| * toBeRemoved = 'c' |
| * return array |
| * </pre> |
| * |
| * </li> |
| * </ol> |
| * |
| * @param array |
| * the given array |
| * @param toBeRemoved |
| * the character to be removed |
| * @return a new array removing given character |
| * |
| */ |
| public static final char[] remove(char[] array, char toBeRemoved) { |
| |
| if (array == null) |
| return null; |
| int length = array.length; |
| if (length == 0) |
| return array; |
| char[] result = null; |
| int count = 0; |
| for (int i = 0; i < length; i++) { |
| char c = array[i]; |
| if (c == toBeRemoved) { |
| if (result == null) { |
| result = new char[length]; |
| System.arraycopy(array, 0, result, 0, i); |
| count = i; |
| } |
| } else if (result != null) { |
| result[count++] = c; |
| } |
| } |
| if (result == null) |
| return array; |
| System.arraycopy(result, 0, result = new char[count], 0, count); |
| return result; |
| } |
| |
| /** |
| * Converts string array to char[][] array <br> |
| * <br> |
| * For example: |
| * <ul> |
| * <li> |
| * |
| * <pre> |
| * array = { "abc", "de" } |
| * return { {'a' , 'b', 'c'}, {'d' , 'e'} } |
| * </pre> |
| * |
| * </li> |
| * </ul> |
| * |
| * @param array |
| * string array |
| * @return char[][] array |
| */ |
| public static final char[][] stringArrayToCharCharArray(String[] array) { |
| if (array == null) { |
| return null; |
| } |
| char[][] result = new char[array.length][]; |
| for (int i = 0; i < array.length; ++i) { |
| result[i] = array[i].toCharArray(); |
| } |
| return result; |
| } |
| |
| /** |
| * @param name |
| * @param separator |
| * @return |
| */ |
| public static String lastSegment(String name, char separator) { |
| int pos = name.lastIndexOf(separator); |
| if (pos >= 0) { |
| return name.substring(pos + 1); |
| } else { |
| return name; |
| } |
| } |
| |
| } |