0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: * Luiz-Otavio Zorzella <zorzella at gmail dot com> - Improve CamelCase algorithm
0011: *******************************************************************************/package org.eclipse.jdt.core.compiler;
0012:
0013: import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
0014:
0015: /**
0016: * This class is a collection of helper methods to manipulate char arrays.
0017: * <p>
0018: * This class is not intended to be instantiated or subclassed by clients.
0019: * </p>
0020: *
0021: * @since 2.1
0022: */
0023: public final class CharOperation {
0024:
0025: /**
0026: * Constant for an empty char array
0027: */
0028: public static final char[] NO_CHAR = new char[0];
0029:
0030: /**
0031: * Constant for an empty char array with two dimensions.
0032: */
0033: public static final char[][] NO_CHAR_CHAR = new char[0][];
0034:
0035: /**
0036: * Constant for an empty String array.
0037: * @since 3.1
0038: */
0039: public static final String[] NO_STRINGS = new String[0];
0040:
0041: /**
0042: * Answers a new array with appending the suffix character at the end of the array.
0043: * <br>
0044: * <br>
0045: * For example:<br>
0046: * <ol>
0047: * <li><pre>
0048: * array = { 'a', 'b' }
0049: * suffix = 'c'
0050: * => result = { 'a', 'b' , 'c' }
0051: * </pre>
0052: * </li>
0053: * <li><pre>
0054: * array = null
0055: * suffix = 'c'
0056: * => result = { 'c' }
0057: * </pre></li>
0058: * </ol>
0059: *
0060: * @param array the array that is concatenated with the suffix character
0061: * @param suffix the suffix character
0062: * @return the new array
0063: */
0064: public static final char[] append(char[] array, char suffix) {
0065: if (array == null)
0066: return new char[] { suffix };
0067: int length = array.length;
0068: System.arraycopy(array, 0, array = new char[length + 1], 0,
0069: length);
0070: array[length] = suffix;
0071: return array;
0072: }
0073:
0074: /**
0075: * Append the given sub-array to the target array starting at the given index in the target array.
0076: * The start of the sub-array is inclusive, the end is exclusive.
0077: * Answers a new target array if it needs to grow, otherwise answers the same target array.
0078: * <br>
0079: * For example:<br>
0080: * <ol>
0081: * <li><pre>
0082: * target = { 'a', 'b', '0' }
0083: * index = 2
0084: * array = { 'c', 'd' }
0085: * start = 0
0086: * end = 1
0087: * => result = { 'a', 'b' , 'c' }
0088: * </pre>
0089: * </li>
0090: * <li><pre>
0091: * target = { 'a', 'b' }
0092: * index = 2
0093: * array = { 'c', 'd' }
0094: * start = 0
0095: * end = 1
0096: * => result = { 'a', 'b' , 'c', '0', '0' , '0' } (new array)
0097: * </pre></li>
0098: * <li><pre>
0099: * target = { 'a', 'b', 'c' }
0100: * index = 1
0101: * array = { 'c', 'd', 'e', 'f' }
0102: * start = 1
0103: * end = 4
0104: * => result = { 'a', 'd' , 'e', 'f', '0', '0', '0', '0' } (new array)
0105: * </pre></li>
0106: * </ol>
0107: *
0108: * @param target the given target
0109: * @param index the given index
0110: * @param array the given array
0111: * @param start the given start index
0112: * @param end the given end index
0113: *
0114: * @return the new array
0115: * @throws NullPointerException if the target array is null
0116: */
0117: public static final char[] append(char[] target, int index,
0118: char[] array, int start, int end) {
0119: int targetLength = target.length;
0120: int subLength = end - start;
0121: int newTargetLength = subLength + index;
0122: if (newTargetLength > targetLength) {
0123: System.arraycopy(target, 0,
0124: target = new char[newTargetLength * 2], 0, index);
0125: }
0126: System.arraycopy(array, start, target, index, subLength);
0127: return target;
0128: }
0129:
0130: /**
0131: * Answers the concatenation of the two arrays. It answers null if the two arrays are null.
0132: * If the first array is null, then the second array is returned.
0133: * If the second array is null, then the first array is returned.
0134: * <br>
0135: * <br>
0136: * For example:
0137: * <ol>
0138: * <li><pre>
0139: * first = null
0140: * second = null
0141: * => result = null
0142: * </pre>
0143: * </li>
0144: * <li><pre>
0145: * first = { { ' a' } }
0146: * second = null
0147: * => result = { { ' a' } }
0148: * </pre>
0149: * </li>
0150: * <li><pre>
0151: * first = null
0152: * second = { { ' a' } }
0153: * => result = { { ' a' } }
0154: * </pre>
0155: * </li>
0156: * <li><pre>
0157: * first = { { ' b' } }
0158: * second = { { ' a' } }
0159: * => result = { { ' b' }, { ' a' } }
0160: * </pre>
0161: * </li>
0162: * </ol>
0163: *
0164: * @param first the first array to concatenate
0165: * @param second the second array to concatenate
0166: * @return the concatenation of the two arrays, or null if the two arrays are null.
0167: */
0168: public static final char[][] arrayConcat(char[][] first,
0169: char[][] second) {
0170: if (first == null)
0171: return second;
0172: if (second == null)
0173: return first;
0174:
0175: int length1 = first.length;
0176: int length2 = second.length;
0177: char[][] result = new char[length1 + length2][];
0178: System.arraycopy(first, 0, result, 0, length1);
0179: System.arraycopy(second, 0, result, length1, length2);
0180: return result;
0181: }
0182:
0183: /**
0184: * Answers true if the pattern matches the given name using CamelCase rules, or
0185: * false otherwise. char[] CamelCase matching does NOT accept explicit wild-cards
0186: * '*' and '?' and is inherently case sensitive.
0187: * <p>
0188: * CamelCase denotes the convention of writing compound names without spaces,
0189: * and capitalizing every term. This function recognizes both upper and lower
0190: * CamelCase, depending whether the leading character is capitalized or not.
0191: * The leading part of an upper CamelCase pattern is assumed to contain a
0192: * sequence of capitals which are appearing in the matching name; e.g. 'NPE' will
0193: * match 'NullPointerException', but not 'NewPerfData'. A lower CamelCase pattern
0194: * uses a lowercase first character. In Java, type names follow the upper
0195: * CamelCase convention, whereas method or field names follow the lower
0196: * CamelCase convention.
0197: * <p>
0198: * The pattern may contain lowercase characters, which will be matched in a case
0199: * sensitive way. These characters must appear in sequence in the name.
0200: * For instance, 'NPExcep' will match 'NullPointerException', but not
0201: * 'NullPointerExCEPTION' or 'NuPoEx' will match 'NullPointerException', but not
0202: * 'NoPointerException'.
0203: * <p>
0204: * Digit characters are treated in a special way. They can be used in the pattern
0205: * but are not always considered as leading character. For instance, both
0206: * 'UTF16DSS' and 'UTFDSS' patterns will match 'UTF16DocumentScannerSupport'.
0207: * <p>
0208: * This method allows prefix match in Camel Case (see
0209: * {@link #camelCaseMatch(char[], char[], boolean)}).
0210: * <p>
0211: * <pre>
0212: * Examples:<ol>
0213: * <li> pattern = { 'N', 'P', 'E' }
0214: * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0215: * result => true</li>
0216: * <li> pattern = { 'N', 'P', 'E' }
0217: * name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0218: * result => true</li>
0219: * <li> pattern = { 'N', 'u', 'P', 'o', 'E', 'x' }
0220: * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0221: * result => true</li>
0222: * <li> pattern = { 'N', 'u', 'P', 'o', 'E', 'x' }
0223: * name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0224: * result => false</li>
0225: * <li> pattern = { 'n', p', 'e' }
0226: * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0227: * result => false</li>
0228: * <li> pattern = { 'I', 'P', 'L', '3' }
0229: * name = { 'I', 'P', 'e', 'r', 's', 'p', 'e', 'c', 't', 'i', 'v', 'e', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '3' }
0230: * result => true</li>
0231: * <li> pattern = { 'H', M' }
0232: * name = { 'H', 'a', 's', 'h', 'M', 'a', 'p', 'E', 'n', 't', 'r', 'y' }
0233: * result => true</li>
0234: * <li>pattern = { 'H', M', 'a', 'p' }
0235: * name = { 'H', 'a', 't', 'M', 'a', 'p', 'p', 'e', 'r' }
0236: * result => true</li>
0237: * </ol></pre>
0238: *
0239: * @param pattern the given pattern
0240: * @param name the given name
0241: * @return true if the pattern matches the given name, false otherwise
0242: * @since 3.2
0243: */
0244: public static final boolean camelCaseMatch(char[] pattern,
0245: char[] name) {
0246: if (pattern == null)
0247: return true; // null pattern is equivalent to '*'
0248: if (name == null)
0249: return false; // null name cannot match
0250:
0251: return camelCaseMatch(pattern, 0, pattern.length, name, 0,
0252: name.length, true/*prefix match*/);
0253: }
0254:
0255: /**
0256: * Answers true if the pattern matches the given name using CamelCase rules, or
0257: * false otherwise. char[] CamelCase matching does NOT accept explicit wild-cards
0258: * '*' and '?' and is inherently case sensitive.
0259: * <p>
0260: * CamelCase denotes the convention of writing compound names without spaces,
0261: * and capitalizing every term. This function recognizes both upper and lower
0262: * CamelCase, depending whether the leading character is capitalized or not.
0263: * The leading part of an upper CamelCase pattern is assumed to contain a
0264: * sequence of capitals which are appearing in the matching name; e.g. 'NPE' will
0265: * match 'NullPointerException', but not 'NewPerfData'. A lower CamelCase pattern
0266: * uses a lowercase first character. In Java, type names follow the upper
0267: * CamelCase convention, whereas method or field names follow the lower
0268: * CamelCase convention.
0269: * <p>
0270: * The pattern may contain lowercase characters, which will be matched in a case
0271: * sensitive way. These characters must appear in sequence in the name.
0272: * For instance, 'NPExcep' will match 'NullPointerException', but not
0273: * 'NullPointerExCEPTION' or 'NuPoEx' will match 'NullPointerException', but not
0274: * 'NoPointerException'.
0275: * <p>
0276: * Digit characters are treated in a special way. They can be used in the pattern
0277: * but are not always considered as leading character. For instance, both
0278: * 'UTF16DSS' and 'UTFDSS' patterns will match 'UTF16DocumentScannerSupport'.
0279: * <p>
0280: * CamelCase may or may not match prefixes depending on the given parameter.
0281: * When the prefix match parameter is <code>true</code>, the given pattern can
0282: * match only a prefix of the given name. For instance, 'HM' , 'HaMa' and 'HMap'
0283: * patterns will all match 'HashMap', 'HatMapper' <b>and</b> 'HashMapEntry'.
0284: * <br>
0285: * Reversely, if the prefix match parameter is <code>false</code>, then pattern
0286: * and name must have <b>exactly</b> the same number of parts, and their last
0287: * parts must be identical if they contain lowercase characters.
0288: * For instance, 'HMap' and 'HaMap' patterns will match 'HashMap' but neither
0289: * 'HashMapEntry' nor 'HatMapper'. Note that when the last part does not contain
0290: * lowercase characters, then the name may end with lowercase characters.
0291: * So, 'HM' pattern will match both 'HashMap' <b>and</b> 'HatMapper' but will not
0292: * match 'HashMapEntry'.
0293: * <p>
0294: * <pre>
0295: * Examples:<ol>
0296: * <li> pattern = { 'N', 'P', 'E' }
0297: * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0298: * result => true</li>
0299: * <li> pattern = { 'N', 'P', 'E' }
0300: * name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0301: * result => true</li>
0302: * <li> pattern = { 'N', 'u', 'P', 'o', 'E', 'x' }
0303: * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0304: * result => true</li>
0305: * <li> pattern = { 'N', 'u', 'P', 'o', 'E', 'x' }
0306: * name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0307: * result => false</li>
0308: * <li> pattern = { 'n', p', 'e' }
0309: * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0310: * result => false</li>
0311: * <li> pattern = { 'I', 'P', 'L', '3' }
0312: * name = { 'I', 'P', 'e', 'r', 's', 'p', 'e', 'c', 't', 'i', 'v', 'e', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '3' }
0313: * result => true</li>
0314: * <li> pattern = { 'H', M' }
0315: * name = { 'H', 'a', 's', 'h', 'M', 'a', 'p', 'E', 'n', 't', 'r', 'y' }
0316: * result => (prefixMatch == true)</li>
0317: * <li> pattern = { 'H', M', 'a', 'p' }
0318: * name = { 'H', 'a', 't', 'M', 'a', 'p', 'p', 'e', 'r' }
0319: * result => (prefixMatch == true)</li>
0320: * </ol></pre>
0321: *
0322: * @param pattern the given pattern
0323: * @param name the given name
0324: * @param prefixMatch flag telling whether the pattern can match name prefix or not.
0325: * <ul>
0326: * <li>For example, when it's <code>true</code>:<br>
0327: * - 'HM' type string pattern will match 'HashMap' and 'HtmlMapper' types,
0328: * but not 'HashMapEntry'<br>
0329: * - 'HMap' type string pattern will match 'HashMap' type but not 'HtmlMapper'.
0330: * </li>
0331: * <li>and, when it's <code>false</code>:<br>
0332: * - 'HM' type string pattern will match both 'HashMap' and 'HtmlMapper'
0333: * and 'HashMapEntry'<br>
0334: * - 'HMap' type string pattern will match both 'HashMap' and 'HtmlMapper'
0335: * types.
0336: * </li>
0337: * </ul>
0338: * @return true if the pattern matches the given name, false otherwise
0339: * @since 3.4
0340: */
0341: public static final boolean camelCaseMatch(char[] pattern,
0342: char[] name, boolean prefixMatch) {
0343: if (pattern == null)
0344: return true; // null pattern is equivalent to '*'
0345: if (name == null)
0346: return false; // null name cannot match
0347:
0348: return camelCaseMatch(pattern, 0, pattern.length, name, 0,
0349: name.length, prefixMatch);
0350: }
0351:
0352: /**
0353: * Answers true if a sub-pattern matches the sub-part of the given name using
0354: * CamelCase rules, or false otherwise. char[] CamelCase matching does NOT
0355: * accept explicit wild-cards '*' and '?' and is inherently case sensitive.
0356: * Can match only subset of name/pattern, considering end positions as non-inclusive.
0357: * The sub-pattern is defined by the patternStart and patternEnd positions.
0358: * <p>
0359: * CamelCase denotes the convention of writing compound names without spaces,
0360: * and capitalizing every term. This function recognizes both upper and lower
0361: * CamelCase, depending whether the leading character is capitalized or not.
0362: * The leading part of an upper CamelCase pattern is assumed to contain a
0363: * sequence of capitals which are appearing in the matching name; e.g. 'NPE' will
0364: * match 'NullPointerException', but not 'NewPerfData'. A lower CamelCase pattern
0365: * uses a lowercase first character. In Java, type names follow the upper
0366: * CamelCase convention, whereas method or field names follow the lower
0367: * CamelCase convention.
0368: * <p>
0369: * The pattern may contain lowercase characters, which will be matched in a case
0370: * sensitive way. These characters must appear in sequence in the name.
0371: * For instance, 'NPExcep' will match 'NullPointerException', but not
0372: * 'NullPointerExCEPTION' or 'NuPoEx' will match 'NullPointerException', but not
0373: * 'NoPointerException'.
0374: * <p>
0375: * Digit characters are treated in a special way. They can be used in the pattern
0376: * but are not always considered as leading character. For instance, both
0377: * 'UTF16DSS' and 'UTFDSS' patterns will match 'UTF16DocumentScannerSupport'.
0378: * <p>
0379: * Digit characters are treated in a special way. They can be used in the pattern
0380: * but are not always considered as leading character. For instance, both
0381: * 'UTF16DSS' and 'UTFDSS' patterns will match 'UTF16DocumentScannerSupport'.
0382: * <p>
0383: * This method allows prefix match in Camel Case (see
0384: * {@link #camelCaseMatch(char[], int, int, char[], int, int, boolean)}).
0385: * <p>
0386: * Examples:
0387: * <ol>
0388: * <li><pre>
0389: * pattern = { 'N', 'P', 'E' }
0390: * patternStart = 0
0391: * patternEnd = 3
0392: * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0393: * nameStart = 0
0394: * nameEnd = 20
0395: * result => true
0396: * </pre>
0397: * </li>
0398: * <li><pre>
0399: * pattern = { 'N', 'P', 'E' }
0400: * patternStart = 0
0401: * patternEnd = 3
0402: * name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0403: * nameStart = 0
0404: * nameEnd = 21
0405: * result => true
0406: * </pre>
0407: * </li>
0408: * <li><pre>
0409: * pattern = { 'N', 'u', 'P', 'o', 'E', 'x' }
0410: * patternStart = 0
0411: * patternEnd = 6
0412: * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0413: * nameStart = 0
0414: * nameEnd = 20
0415: * result => true
0416: * </pre>
0417: * </li>
0418: * <li><pre>
0419: * pattern = { 'N', 'u', 'P', 'o', 'E', 'x' }
0420: * patternStart = 0
0421: * patternEnd = 6
0422: * name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0423: * nameStart = 0
0424: * nameEnd = 21
0425: * result => false
0426: * </pre>
0427: * </li>
0428: * <li><pre>
0429: * pattern = { 'n', p', 'e' }
0430: * patternStart = 0
0431: * patternEnd = 3
0432: * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0433: * nameStart = 0
0434: * nameEnd = 20
0435: * result => false
0436: * </pre>
0437: * </li>
0438: * <li><pre>
0439: * pattern = { 'I', 'P', 'L', '3' }
0440: * patternStart = 0
0441: * patternEnd = 4
0442: * name = { 'I', 'P', 'e', 'r', 's', 'p', 'e', 'c', 't', 'i', 'v', 'e', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '3' }
0443: * nameStart = 0
0444: * nameEnd = 21
0445: * result => true
0446: * </pre>
0447: * </li>
0448: * </ol>
0449: *
0450: * @param pattern the given pattern
0451: * @param patternStart the start index of the pattern, inclusive
0452: * @param patternEnd the end index of the pattern, exclusive
0453: * @param name the given name
0454: * @param nameStart the start index of the name, inclusive
0455: * @param nameEnd the end index of the name, exclusive
0456: * @return true if a sub-pattern matches the sub-part of the given name, false otherwise
0457: * @since 3.2
0458: */
0459: public static final boolean camelCaseMatch(char[] pattern,
0460: int patternStart, int patternEnd, char[] name,
0461: int nameStart, int nameEnd) {
0462: return camelCaseMatch(pattern, patternStart, patternEnd, name,
0463: nameStart, nameEnd, true/*prefix match*/);
0464: }
0465:
0466: /**
0467: * Answers true if a sub-pattern matches the sub-part of the given name using
0468: * CamelCase rules, or false otherwise. char[] CamelCase matching does NOT
0469: * accept explicit wild-cards '*' and '?' and is inherently case sensitive.
0470: * Can match only subset of name/pattern, considering end positions as
0471: * non-inclusive. The sub-pattern is defined by the patternStart and patternEnd
0472: * positions.
0473: * <p>
0474: * CamelCase denotes the convention of writing compound names without spaces,
0475: * and capitalizing every term. This function recognizes both upper and lower
0476: * CamelCase, depending whether the leading character is capitalized or not.
0477: * The leading part of an upper CamelCase pattern is assumed to contain
0478: * a sequence of capitals which are appearing in the matching name; e.g. 'NPE' will
0479: * match 'NullPointerException', but not 'NewPerfData'. A lower CamelCase pattern
0480: * uses a lowercase first character. In Java, type names follow the upper
0481: * CamelCase convention, whereas method or field names follow the lower
0482: * CamelCase convention.
0483: * <p>
0484: * The pattern may contain lowercase characters, which will be matched in a case
0485: * sensitive way. These characters must appear in sequence in the name.
0486: * For instance, 'NPExcep' will match 'NullPointerException', but not
0487: * 'NullPointerExCEPTION' or 'NuPoEx' will match 'NullPointerException', but not
0488: * 'NoPointerException'.
0489: * <p>
0490: * Digit characters are treated in a special way. They can be used in the pattern
0491: * but are not always considered as leading character. For instance, both
0492: * 'UTF16DSS' and 'UTFDSS' patterns will match 'UTF16DocumentScannerSupport'.
0493: * <p>
0494: * CamelCase may or may not match prefixes depending on the given parameter.
0495: * When the prefix match parameter is <code>true</code>, the given pattern can
0496: * match only a prefix of the given name. For instance, 'HM' , 'HaMa' and 'HMap'
0497: * patterns will all match 'HashMap', 'HatMapper' <b>and</b> 'HashMapEntry'.
0498: * <br>
0499: * Reversely, if the prefix match parameter is <code>false</code>, then pattern
0500: * and name must have <b>exactly</b> the same number of parts, and their last
0501: * parts must be identical if they contain lowercase characters.
0502: * For instance, 'HMap' and 'HaMap' patterns will match 'HashMap' but neither
0503: * 'HashMapEntry' nor 'HatMapper'. Note that when the last part does not contain
0504: * lowercase characters, then the name may end with lowercase characters.
0505: * So, 'HM' pattern will match both 'HashMap' <b>and</b> 'HatMapper' but will not
0506: * match 'HashMapEntry'.
0507: * <p>
0508: * <pre>
0509: * Examples:
0510: * <ol>
0511: * <li> pattern = { 'N', 'P', 'E' }
0512: * patternStart = 0
0513: * patternEnd = 3
0514: * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0515: * nameStart = 0
0516: * nameEnd = 20
0517: * result => true</li>
0518: * <li> pattern = { 'N', 'P', 'E' }
0519: * patternStart = 0
0520: * patternEnd = 3
0521: * name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0522: * nameStart = 0
0523: * nameEnd = 21
0524: * result => true</li>
0525: * <li> pattern = { 'N', 'u', 'P', 'o', 'E', 'x' }
0526: * patternStart = 0
0527: * patternEnd = 6
0528: * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0529: * nameStart = 0
0530: * nameEnd = 20
0531: * result => true</li>
0532: * <li> pattern = { 'N', 'u', 'P', 'o', 'E', 'x' }
0533: * patternStart = 0
0534: * patternEnd = 6
0535: * name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0536: * nameStart = 0
0537: * nameEnd = 21
0538: * result => false</li>
0539: * <li> pattern = { 'n', p', 'e' }
0540: * patternStart = 0
0541: * patternEnd = 3
0542: * name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
0543: * nameStart = 0
0544: * nameEnd = 20
0545: * result => false</li>
0546: * <li> pattern = { 'I', 'P', 'L', '3' }
0547: * patternStart = 0
0548: * patternEnd = 4
0549: * name = { 'I', 'P', 'e', 'r', 's', 'p', 'e', 'c', 't', 'i', 'v', 'e', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '3' }
0550: * nameStart = 0
0551: * nameEnd = 21
0552: * result => true</li>
0553: * <li> pattern = { 'H', M' }
0554: * patternStart = 0
0555: * patternEnd = 2
0556: * name = { 'H', 'a', 's', 'h', 'M', 'a', 'p', 'E', 'n', 't', 'r', 'y' }
0557: * nameStart = 0
0558: * nameEnd = 12
0559: * result => (exactMode == false)</li>
0560: * <li> pattern = { 'H', M', 'a', 'p' }
0561: * patternStart = 0
0562: * patternEnd = 4
0563: * name = { 'H', 'a', 't', 'M', 'a', 'p', 'p', 'e', 'r' }
0564: * nameStart = 0
0565: * nameEnd = 9
0566: * result => (exactMode == false)</li>
0567: * </ol>
0568: * </pre>
0569: *
0570: * @param pattern the given pattern
0571: * @param patternStart the start index of the pattern, inclusive
0572: * @param patternEnd the end index of the pattern, exclusive
0573: * @param name the given name
0574: * @param nameStart the start index of the name, inclusive
0575: * @param nameEnd the end index of the name, exclusive
0576: * @param prefixMatch flag telling whether the pattern can match name prefix or not.
0577: * <ul>
0578: * <li>For example, when it's <code>true</code>:<br>
0579: * - 'HM' type string pattern will match 'HashMap' and 'HtmlMapper' types,
0580: * but not 'HashMapEntry'<br>
0581: * - 'HMap' type string pattern will match 'HashMap' type but not 'HtmlMapper'.
0582: * </li>
0583: * <li>and, when it's <code>false</code>:<br>
0584: * - 'HM' type string pattern will match both 'HashMap' and 'HtmlMapper'
0585: * and 'HashMapEntry'<br>
0586: * - 'HMap' type string pattern will match both 'HashMap' and 'HtmlMapper'
0587: * types.
0588: * </li>
0589: * </ul>
0590: * @return true if a sub-pattern matches the sub-part of the given name, false otherwise
0591: * @since 3.4
0592: */
0593: public static final boolean camelCaseMatch(char[] pattern,
0594: int patternStart, int patternEnd, char[] name,
0595: int nameStart, int nameEnd, boolean prefixMatch) {
0596: if (name == null)
0597: return false; // null name cannot match
0598: if (pattern == null)
0599: return true; // null pattern is equivalent to '*'
0600: if (patternEnd < 0)
0601: patternEnd = pattern.length;
0602: if (nameEnd < 0)
0603: nameEnd = name.length;
0604:
0605: if (patternEnd <= patternStart)
0606: return nameEnd <= nameStart;
0607: if (nameEnd <= nameStart)
0608: return false;
0609: // check first pattern char
0610: if (name[nameStart] != pattern[patternStart]) {
0611: // first char must strictly match (upper/lower)
0612: return false;
0613: }
0614:
0615: char patternChar, nameChar;
0616: int iPattern = patternStart;
0617: int iName = nameStart;
0618:
0619: // Main loop is on pattern characters
0620: while (true) {
0621:
0622: iPattern++;
0623: iName++;
0624:
0625: if (iPattern == patternEnd) { // we have exhausted pattern...
0626: // it's a match if not exact mode or name is also exhausted
0627: if (prefixMatch || iName == nameEnd)
0628: return true;
0629:
0630: // it's not a match if last pattern character is a lowercase
0631: if ((patternChar = pattern[iPattern - 1]) < ScannerHelper.MAX_OBVIOUS) {
0632: if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[patternChar] & (ScannerHelper.C_UPPER_LETTER | ScannerHelper.C_DIGIT)) == 0) {
0633: return false;
0634: }
0635: } else if (Character.isJavaIdentifierPart(patternChar)
0636: && !Character.isUpperCase(patternChar)
0637: && !Character.isDigit(patternChar)) {
0638: return false;
0639: }
0640:
0641: // it's a match only if name has no more uppercase characters (exact mode)
0642: while (true) {
0643: if (iName == nameEnd) {
0644: // we have exhausted name, so it's a match
0645: return true;
0646: }
0647: nameChar = name[iName];
0648: if (nameChar < ScannerHelper.MAX_OBVIOUS) {
0649: if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[nameChar] & ScannerHelper.C_UPPER_LETTER) != 0) {
0650: // nameChar is uppercase, so it's not a match
0651: return false;
0652: }
0653: } else if (!Character
0654: .isJavaIdentifierPart(nameChar)
0655: || Character.isUpperCase(nameChar)) {
0656: return false;
0657: }
0658: iName++;
0659: }
0660: }
0661:
0662: if (iName == nameEnd) {
0663: // We have exhausted name (and not pattern), so it's not a match
0664: return false;
0665: }
0666:
0667: // For as long as we're exactly matching, bring it on (even if it's a lower case character)
0668: if ((patternChar = pattern[iPattern]) == name[iName]) {
0669: continue;
0670: }
0671:
0672: // If characters are not equals, then it's not a match if patternChar is lowercase
0673: if (patternChar < ScannerHelper.MAX_OBVIOUS) {
0674: if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[patternChar] & (ScannerHelper.C_UPPER_LETTER | ScannerHelper.C_DIGIT)) == 0) {
0675: return false;
0676: }
0677: } else if (Character.isJavaIdentifierPart(patternChar)
0678: && !Character.isUpperCase(patternChar)
0679: && !Character.isDigit(patternChar)) {
0680: return false;
0681: }
0682:
0683: // patternChar is uppercase, so let's find the next uppercase in name
0684: while (true) {
0685: if (iName == nameEnd) {
0686: // We have exhausted name (and not pattern), so it's not a match
0687: return false;
0688: }
0689:
0690: nameChar = name[iName];
0691: if (nameChar < ScannerHelper.MAX_OBVIOUS) {
0692: int charNature = ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[nameChar];
0693: if ((charNature & (ScannerHelper.C_LOWER_LETTER | ScannerHelper.C_SPECIAL)) != 0) {
0694: // nameChar is lowercase
0695: iName++;
0696: } else if ((charNature & ScannerHelper.C_DIGIT) != 0) {
0697: // nameChar is digit => break if the digit is current pattern character otherwise consume it
0698: if (patternChar == nameChar)
0699: break;
0700: iName++;
0701: // nameChar is uppercase...
0702: } else if (patternChar != nameChar) {
0703: //.. and it does not match patternChar, so it's not a match
0704: return false;
0705: } else {
0706: //.. and it matched patternChar. Back to the big loop
0707: break;
0708: }
0709: }
0710: // Same tests for non-obvious characters
0711: else if (Character.isJavaIdentifierPart(nameChar)
0712: && !Character.isUpperCase(nameChar)) {
0713: iName++;
0714: } else if (Character.isDigit(nameChar)) {
0715: if (patternChar == nameChar)
0716: break;
0717: iName++;
0718: } else if (patternChar != nameChar) {
0719: return false;
0720: } else {
0721: break;
0722: }
0723: }
0724: // At this point, either name has been exhausted, or it is at an uppercase letter.
0725: // Since pattern is also at an uppercase letter
0726: }
0727: }
0728:
0729: /**
0730: * Returns the char arrays as an array of Strings
0731: *
0732: * @param charArrays the char array to convert
0733: * @return the char arrays as an array of Strings or null if the given char arrays is null.
0734: * @since 3.0
0735: */
0736: public static String[] charArrayToStringArray(char[][] charArrays) {
0737: if (charArrays == null)
0738: return null;
0739: int length = charArrays.length;
0740: if (length == 0)
0741: return NO_STRINGS;
0742: String[] strings = new String[length];
0743: for (int i = 0; i < length; i++)
0744: strings[i] = new String(charArrays[i]);
0745: return strings;
0746: }
0747:
0748: /**
0749: * Returns the char array as a String
0750:
0751: * @param charArray the char array to convert
0752: * @return the char array as a String or null if the given char array is null.
0753: * @since 3.0
0754: */
0755: public static String charToString(char[] charArray) {
0756: if (charArray == null)
0757: return null;
0758: return new String(charArray);
0759: }
0760:
0761: /**
0762: * Answers a new array adding the second array at the end of first array.
0763: * It answers null if the first and second are null.
0764: * If the first array is null, then a new array char[][] is created with second.
0765: * If the second array is null, then the first array is returned.
0766: * <br>
0767: * <br>
0768: * For example:
0769: * <ol>
0770: * <li><pre>
0771: * first = null
0772: * second = { 'a' }
0773: * => result = { { ' a' } }
0774: * </pre>
0775: * <li><pre>
0776: * first = { { ' a' } }
0777: * second = null
0778: * => result = { { ' a' } }
0779: * </pre>
0780: * </li>
0781: * <li><pre>
0782: * first = { { ' a' } }
0783: * second = { ' b' }
0784: * => result = { { ' a' } , { ' b' } }
0785: * </pre>
0786: * </li>
0787: * </ol>
0788: *
0789: * @param first the first array to concatenate
0790: * @param second the array to add at the end of the first array
0791: * @return a new array adding the second array at the end of first array, or null if the two arrays are null.
0792: */
0793: public static final char[][] arrayConcat(char[][] first,
0794: char[] second) {
0795: if (second == null)
0796: return first;
0797: if (first == null)
0798: return new char[][] { second };
0799:
0800: int length = first.length;
0801: char[][] result = new char[length + 1][];
0802: System.arraycopy(first, 0, result, 0, length);
0803: result[length] = second;
0804: return result;
0805: }
0806:
0807: /**
0808: * Compares the two char arrays lexicographically.
0809: *
0810: * Returns a negative integer if array1 lexicographically precedes the array2,
0811: * a positive integer if this array1 lexicographically follows the array2, or
0812: * zero if both arrays are equal.
0813: *
0814: * @param array1 the first given array
0815: * @param array2 the second given array
0816: * @return the returned value of the comparison between array1 and array2
0817: * @throws NullPointerException if one of the arrays is null
0818: * @since 3.3
0819: */
0820: public static final int compareTo(char[] array1, char[] array2) {
0821: int length1 = array1.length;
0822: int length2 = array2.length;
0823: int min = Math.min(length1, length2);
0824: for (int i = 0; i < min; i++) {
0825: if (array1[i] != array2[i]) {
0826: return array1[i] - array2[i];
0827: }
0828: }
0829: return length1 - length2;
0830: }
0831:
0832: /**
0833: * Compares the contents of the two arrays array and prefix. Returns
0834: * <ul>
0835: * <li>zero if the array starts with the prefix contents</li>
0836: * <li>the difference between the first two characters that are not equal </li>
0837: * <li>one if array length is lower than the prefix length and that the prefix starts with the
0838: * array contents.</li>
0839: * </ul>
0840: * <p>
0841: * For example:
0842: * <ol>
0843: * <li><pre>
0844: * array = null
0845: * prefix = null
0846: * => result = NullPointerException
0847: * </pre>
0848: * </li>
0849: * <li><pre>
0850: * array = { 'a', 'b', 'c', 'd', 'e' }
0851: * prefix = { 'a', 'b', 'c'}
0852: * => result = 0
0853: * </pre>
0854: * </li>
0855: * <li><pre>
0856: * array = { 'a', 'b', 'c', 'd', 'e' }
0857: * prefix = { 'a', 'B', 'c'}
0858: * => result = 32
0859: * </pre>
0860: * </li>
0861: * <li><pre>
0862: * array = { 'd', 'b', 'c', 'd', 'e' }
0863: * prefix = { 'a', 'b', 'c'}
0864: * => result = 3
0865: * </pre>
0866: * </li>
0867: * <li><pre>
0868: * array = { 'a', 'b', 'c', 'd', 'e' }
0869: * prefix = { 'd', 'b', 'c'}
0870: * => result = -3
0871: * </pre>
0872: * </li>
0873: * <li><pre>
0874: * array = { 'a', 'a', 'c', 'd', 'e' }
0875: * prefix = { 'a', 'e', 'c'}
0876: * => result = -4
0877: * </pre>
0878: * </li>
0879: * </ol>
0880: * </p>
0881: *
0882: * @param array the given array
0883: * @param prefix the given prefix
0884: * @return the result of the comparison (>=0 if array>prefix)
0885: * @throws NullPointerException if either array or prefix is null
0886: */
0887: public static final int compareWith(char[] array, char[] prefix) {
0888: int arrayLength = array.length;
0889: int prefixLength = prefix.length;
0890: int min = Math.min(arrayLength, prefixLength);
0891: int i = 0;
0892: while (min-- != 0) {
0893: char c1 = array[i];
0894: char c2 = prefix[i++];
0895: if (c1 != c2)
0896: return c1 - c2;
0897: }
0898: if (prefixLength == i)
0899: return 0;
0900: return -1; // array is shorter than prefix (e.g. array:'ab' < prefix:'abc').
0901: }
0902:
0903: /**
0904: * Answers the concatenation of the two arrays. It answers null if the two arrays are null.
0905: * If the first array is null, then the second array is returned.
0906: * If the second array is null, then the first array is returned.
0907: * <br>
0908: * <br>
0909: * For example:
0910: * <ol>
0911: * <li><pre>
0912: * first = null
0913: * second = { 'a' }
0914: * => result = { ' a' }
0915: * </pre>
0916: * </li>
0917: * <li><pre>
0918: * first = { ' a' }
0919: * second = null
0920: * => result = { ' a' }
0921: * </pre>
0922: * </li>
0923: * <li><pre>
0924: * first = { ' a' }
0925: * second = { ' b' }
0926: * => result = { ' a' , ' b' }
0927: * </pre>
0928: * </li>
0929: * </ol>
0930: *
0931: * @param first the first array to concatenate
0932: * @param second the second array to concatenate
0933: * @return the concatenation of the two arrays, or null if the two arrays are null.
0934: */
0935: public static final char[] concat(char[] first, char[] second) {
0936: if (first == null)
0937: return second;
0938: if (second == null)
0939: return first;
0940:
0941: int length1 = first.length;
0942: int length2 = second.length;
0943: char[] result = new char[length1 + length2];
0944: System.arraycopy(first, 0, result, 0, length1);
0945: System.arraycopy(second, 0, result, length1, length2);
0946: return result;
0947: }
0948:
0949: /**
0950: * Answers the concatenation of the three arrays. It answers null if the three arrays are null.
0951: * If first is null, it answers the concatenation of second and third.
0952: * If second is null, it answers the concatenation of first and third.
0953: * If third is null, it answers the concatenation of first and second.
0954: * <br>
0955: * <br>
0956: * For example:
0957: * <ol>
0958: * <li><pre>
0959: * first = null
0960: * second = { 'a' }
0961: * third = { 'b' }
0962: * => result = { ' a', 'b' }
0963: * </pre>
0964: * </li>
0965: * <li><pre>
0966: * first = { 'a' }
0967: * second = null
0968: * third = { 'b' }
0969: * => result = { ' a', 'b' }
0970: * </pre>
0971: * </li>
0972: * <li><pre>
0973: * first = { 'a' }
0974: * second = { 'b' }
0975: * third = null
0976: * => result = { ' a', 'b' }
0977: * </pre>
0978: * </li>
0979: * <li><pre>
0980: * first = null
0981: * second = null
0982: * third = null
0983: * => result = null
0984: * </pre>
0985: * </li>
0986: * <li><pre>
0987: * first = { 'a' }
0988: * second = { 'b' }
0989: * third = { 'c' }
0990: * => result = { 'a', 'b', 'c' }
0991: * </pre>
0992: * </li>
0993: * </ol>
0994: *
0995: * @param first the first array to concatenate
0996: * @param second the second array to concatenate
0997: * @param third the third array to concatenate
0998: *
0999: * @return the concatenation of the three arrays, or null if the three arrays are null.
1000: */
1001: public static final char[] concat(char[] first, char[] second,
1002: char[] third) {
1003: if (first == null)
1004: return concat(second, third);
1005: if (second == null)
1006: return concat(first, third);
1007: if (third == null)
1008: return concat(first, second);
1009:
1010: int length1 = first.length;
1011: int length2 = second.length;
1012: int length3 = third.length;
1013: char[] result = new char[length1 + length2 + length3];
1014: System.arraycopy(first, 0, result, 0, length1);
1015: System.arraycopy(second, 0, result, length1, length2);
1016: System.arraycopy(third, 0, result, length1 + length2, length3);
1017: return result;
1018: }
1019:
1020: /**
1021: * Answers the concatenation of the two arrays inserting the separator character between the two arrays.
1022: * It answers null if the two arrays are null.
1023: * If the first array is null, then the second array is returned.
1024: * If the second array is null, then the first array is returned.
1025: * <br>
1026: * <br>
1027: * For example:
1028: * <ol>
1029: * <li><pre>
1030: * first = null
1031: * second = { 'a' }
1032: * separator = '/'
1033: * => result = { ' a' }
1034: * </pre>
1035: * </li>
1036: * <li><pre>
1037: * first = { ' a' }
1038: * second = null
1039: * separator = '/'
1040: * => result = { ' a' }
1041: * </pre>
1042: * </li>
1043: * <li><pre>
1044: * first = { ' a' }
1045: * second = { ' b' }
1046: * separator = '/'
1047: * => result = { ' a' , '/', 'b' }
1048: * </pre>
1049: * </li>
1050: * </ol>
1051: *
1052: * @param first the first array to concatenate
1053: * @param second the second array to concatenate
1054: * @param separator the character to insert
1055: * @return the concatenation of the two arrays inserting the separator character
1056: * between the two arrays , or null if the two arrays are null.
1057: */
1058: public static final char[] concat(char[] first, char[] second,
1059: char separator) {
1060: if (first == null)
1061: return second;
1062: if (second == null)
1063: return first;
1064:
1065: int length1 = first.length;
1066: if (length1 == 0)
1067: return second;
1068: int length2 = second.length;
1069: if (length2 == 0)
1070: return first;
1071:
1072: char[] result = new char[length1 + length2 + 1];
1073: System.arraycopy(first, 0, result, 0, length1);
1074: result[length1] = separator;
1075: System.arraycopy(second, 0, result, length1 + 1, length2);
1076: return result;
1077: }
1078:
1079: /**
1080: * Answers the concatenation of the three arrays inserting the sep1 character between the
1081: * first two arrays and sep2 between the last two.
1082: * It answers null if the three arrays are null.
1083: * If the first array is null, then it answers the concatenation of second and third inserting
1084: * the sep2 character between them.
1085: * If the second array is null, then it answers the concatenation of first and third inserting
1086: * the sep1 character between them.
1087: * If the third array is null, then it answers the concatenation of first and second inserting
1088: * the sep1 character between them.
1089: * <br>
1090: * <br>
1091: * For example:
1092: * <ol>
1093: * <li><pre>
1094: * first = null
1095: * sep1 = '/'
1096: * second = { 'a' }
1097: * sep2 = ':'
1098: * third = { 'b' }
1099: * => result = { ' a' , ':', 'b' }
1100: * </pre>
1101: * </li>
1102: * <li><pre>
1103: * first = { 'a' }
1104: * sep1 = '/'
1105: * second = null
1106: * sep2 = ':'
1107: * third = { 'b' }
1108: * => result = { ' a' , '/', 'b' }
1109: * </pre>
1110: * </li>
1111: * <li><pre>
1112: * first = { 'a' }
1113: * sep1 = '/'
1114: * second = { 'b' }
1115: * sep2 = ':'
1116: * third = null
1117: * => result = { ' a' , '/', 'b' }
1118: * </pre>
1119: * </li>
1120: * <li><pre>
1121: * first = { 'a' }
1122: * sep1 = '/'
1123: * second = { 'b' }
1124: * sep2 = ':'
1125: * third = { 'c' }
1126: * => result = { ' a' , '/', 'b' , ':', 'c' }
1127: * </pre>
1128: * </li>
1129: * </ol>
1130: *
1131: * @param first the first array to concatenate
1132: * @param sep1 the character to insert
1133: * @param second the second array to concatenate
1134: * @param sep2 the character to insert
1135: * @param third the second array to concatenate
1136: * @return the concatenation of the three arrays inserting the sep1 character between the
1137: * two arrays and sep2 between the last two.
1138: */
1139: public static final char[] concat(char[] first, char sep1,
1140: char[] second, char sep2, char[] third) {
1141: if (first == null)
1142: return concat(second, third, sep2);
1143: if (second == null)
1144: return concat(first, third, sep1);
1145: if (third == null)
1146: return concat(first, second, sep1);
1147:
1148: int length1 = first.length;
1149: int length2 = second.length;
1150: int length3 = third.length;
1151: char[] result = new char[length1 + length2 + length3 + 2];
1152: System.arraycopy(first, 0, result, 0, length1);
1153: result[length1] = sep1;
1154: System.arraycopy(second, 0, result, length1 + 1, length2);
1155: result[length1 + length2 + 1] = sep2;
1156: System.arraycopy(third, 0, result, length1 + length2 + 2,
1157: length3);
1158: return result;
1159: }
1160:
1161: /**
1162: * Answers a new array with prepending the prefix character and appending the suffix
1163: * character at the end of the array. If array is null, it answers a new array containing the
1164: * prefix and the suffix characters.
1165: * <br>
1166: * <br>
1167: * For example:<br>
1168: * <ol>
1169: * <li><pre>
1170: * prefix = 'a'
1171: * array = { 'b' }
1172: * suffix = 'c'
1173: * => result = { 'a', 'b' , 'c' }
1174: * </pre>
1175: * </li>
1176: * <li><pre>
1177: * prefix = 'a'
1178: * array = null
1179: * suffix = 'c'
1180: * => result = { 'a', 'c' }
1181: * </pre></li>
1182: * </ol>
1183: *
1184: * @param prefix the prefix character
1185: * @param array the array that is concatenated with the prefix and suffix characters
1186: * @param suffix the suffix character
1187: * @return the new array
1188: */
1189: public static final char[] concat(char prefix, char[] array,
1190: char suffix) {
1191: if (array == null)
1192: return new char[] { prefix, suffix };
1193:
1194: int length = array.length;
1195: char[] result = new char[length + 2];
1196: result[0] = prefix;
1197: System.arraycopy(array, 0, result, 1, length);
1198: result[length + 1] = suffix;
1199: return result;
1200: }
1201:
1202: /**
1203: * Answers the concatenation of the given array parts using the given separator between each
1204: * part and appending the given name at the end.
1205: * <br>
1206: * <br>
1207: * For example:<br>
1208: * <ol>
1209: * <li><pre>
1210: * name = { 'c' }
1211: * array = { { 'a' }, { 'b' } }
1212: * separator = '.'
1213: * => result = { 'a', '.', 'b' , '.', 'c' }
1214: * </pre>
1215: * </li>
1216: * <li><pre>
1217: * name = null
1218: * array = { { 'a' }, { 'b' } }
1219: * separator = '.'
1220: * => result = { 'a', '.', 'b' }
1221: * </pre></li>
1222: * <li><pre>
1223: * name = { ' c' }
1224: * array = null
1225: * separator = '.'
1226: * => result = { 'c' }
1227: * </pre></li>
1228: * </ol>
1229: *
1230: * @param name the given name
1231: * @param array the given array
1232: * @param separator the given separator
1233: * @return the concatenation of the given array parts using the given separator between each
1234: * part and appending the given name at the end
1235: */
1236: public static final char[] concatWith(char[] name, char[][] array,
1237: char separator) {
1238: int nameLength = name == null ? 0 : name.length;
1239: if (nameLength == 0)
1240: return concatWith(array, separator);
1241:
1242: int length = array == null ? 0 : array.length;
1243: if (length == 0)
1244: return name;
1245:
1246: int size = nameLength;
1247: int index = length;
1248: while (--index >= 0)
1249: if (array[index].length > 0)
1250: size += array[index].length + 1;
1251: char[] result = new char[size];
1252: index = size;
1253: for (int i = length - 1; i >= 0; i--) {
1254: int subLength = array[i].length;
1255: if (subLength > 0) {
1256: index -= subLength;
1257: System.arraycopy(array[i], 0, result, index, subLength);
1258: result[--index] = separator;
1259: }
1260: }
1261: System.arraycopy(name, 0, result, 0, nameLength);
1262: return result;
1263: }
1264:
1265: /**
1266: * Answers the concatenation of the given array parts using the given separator between each
1267: * part and appending the given name at the end.
1268: * <br>
1269: * <br>
1270: * For example:<br>
1271: * <ol>
1272: * <li><pre>
1273: * name = { 'c' }
1274: * array = { { 'a' }, { 'b' } }
1275: * separator = '.'
1276: * => result = { 'a', '.', 'b' , '.', 'c' }
1277: * </pre>
1278: * </li>
1279: * <li><pre>
1280: * name = null
1281: * array = { { 'a' }, { 'b' } }
1282: * separator = '.'
1283: * => result = { 'a', '.', 'b' }
1284: * </pre></li>
1285: * <li><pre>
1286: * name = { ' c' }
1287: * array = null
1288: * separator = '.'
1289: * => result = { 'c' }
1290: * </pre></li>
1291: * </ol>
1292: *
1293: * @param array the given array
1294: * @param name the given name
1295: * @param separator the given separator
1296: * @return the concatenation of the given array parts using the given separator between each
1297: * part and appending the given name at the end
1298: */
1299: public static final char[] concatWith(char[][] array, char[] name,
1300: char separator) {
1301: int nameLength = name == null ? 0 : name.length;
1302: if (nameLength == 0)
1303: return concatWith(array, separator);
1304:
1305: int length = array == null ? 0 : array.length;
1306: if (length == 0)
1307: return name;
1308:
1309: int size = nameLength;
1310: int index = length;
1311: while (--index >= 0)
1312: if (array[index].length > 0)
1313: size += array[index].length + 1;
1314: char[] result = new char[size];
1315: index = 0;
1316: for (int i = 0; i < length; i++) {
1317: int subLength = array[i].length;
1318: if (subLength > 0) {
1319: System.arraycopy(array[i], 0, result, index, subLength);
1320: index += subLength;
1321: result[index++] = separator;
1322: }
1323: }
1324: System.arraycopy(name, 0, result, index, nameLength);
1325: return result;
1326: }
1327:
1328: /**
1329: * Answers the concatenation of the given array parts using the given separator between each part.
1330: * <br>
1331: * <br>
1332: * For example:<br>
1333: * <ol>
1334: * <li><pre>
1335: * array = { { 'a' }, { 'b' } }
1336: * separator = '.'
1337: * => result = { 'a', '.', 'b' }
1338: * </pre>
1339: * </li>
1340: * <li><pre>
1341: * array = null
1342: * separator = '.'
1343: * => result = { }
1344: * </pre></li>
1345: * </ol>
1346: *
1347: * @param array the given array
1348: * @param separator the given separator
1349: * @return the concatenation of the given array parts using the given separator between each part
1350: */
1351: public static final char[] concatWith(char[][] array, char separator) {
1352: int length = array == null ? 0 : array.length;
1353: if (length == 0)
1354: return CharOperation.NO_CHAR;
1355:
1356: int size = length - 1;
1357: int index = length;
1358: while (--index >= 0) {
1359: if (array[index].length == 0)
1360: size--;
1361: else
1362: size += array[index].length;
1363: }
1364: if (size <= 0)
1365: return CharOperation.NO_CHAR;
1366: char[] result = new char[size];
1367: index = length;
1368: while (--index >= 0) {
1369: length = array[index].length;
1370: if (length > 0) {
1371: System.arraycopy(array[index], 0, result,
1372: (size -= length), length);
1373: if (--size >= 0)
1374: result[size] = separator;
1375: }
1376: }
1377: return result;
1378: }
1379:
1380: /**
1381: * Answers true if the array contains an occurrence of character, false otherwise.
1382: *
1383: * <br>
1384: * <br>
1385: * For example:
1386: * <ol>
1387: * <li><pre>
1388: * character = 'c'
1389: * array = { { ' a' }, { ' b' } }
1390: * result => false
1391: * </pre>
1392: * </li>
1393: * <li><pre>
1394: * character = 'a'
1395: * array = { { ' a' }, { ' b' } }
1396: * result => true
1397: * </pre>
1398: * </li>
1399: * </ol>
1400: *
1401: * @param character the character to search
1402: * @param array the array in which the search is done
1403: * @return true if the array contains an occurrence of character, false otherwise.
1404: * @throws NullPointerException if array is null.
1405: */
1406: public static final boolean contains(char character, char[][] array) {
1407: for (int i = array.length; --i >= 0;) {
1408: char[] subarray = array[i];
1409: for (int j = subarray.length; --j >= 0;)
1410: if (subarray[j] == character)
1411: return true;
1412: }
1413: return false;
1414: }
1415:
1416: /**
1417: * Answers true if the array contains an occurrence of character, false otherwise.
1418: *
1419: * <br>
1420: * <br>
1421: * For example:
1422: * <ol>
1423: * <li><pre>
1424: * character = 'c'
1425: * array = { ' b' }
1426: * result => false
1427: * </pre>
1428: * </li>
1429: * <li><pre>
1430: * character = 'a'
1431: * array = { ' a' , ' b' }
1432: * result => true
1433: * </pre>
1434: * </li>
1435: * </ol>
1436: *
1437: * @param character the character to search
1438: * @param array the array in which the search is done
1439: * @return true if the array contains an occurrence of character, false otherwise.
1440: * @throws NullPointerException if array is null.
1441: */
1442: public static final boolean contains(char character, char[] array) {
1443: for (int i = array.length; --i >= 0;)
1444: if (array[i] == character)
1445: return true;
1446: return false;
1447: }
1448:
1449: /**
1450: * Answers true if the array contains an occurrence of one of the characters, false otherwise.
1451: *
1452: * <br>
1453: * <br>
1454: * For example:
1455: * <ol>
1456: * <li><pre>
1457: * characters = { 'c', 'd' }
1458: * array = { 'a', ' b' }
1459: * result => false
1460: * </pre>
1461: * </li>
1462: * <li><pre>
1463: * characters = { 'c', 'd' }
1464: * array = { 'a', ' b', 'c' }
1465: * result => true
1466: * </pre>
1467: * </li>
1468: * </ol>
1469: *
1470: * @param characters the characters to search
1471: * @param array the array in which the search is done
1472: * @return true if the array contains an occurrence of one of the characters, false otherwise.
1473: * @throws NullPointerException if array is null.
1474: * @since 3.1
1475: */
1476: public static final boolean contains(char[] characters, char[] array) {
1477: for (int i = array.length; --i >= 0;)
1478: for (int j = characters.length; --j >= 0;)
1479: if (array[i] == characters[j])
1480: return true;
1481: return false;
1482: }
1483:
1484: /**
1485: * Answers a deep copy of the toCopy array.
1486: *
1487: * @param toCopy the array to copy
1488: * @return a deep copy of the toCopy array.
1489: */
1490:
1491: public static final char[][] deepCopy(char[][] toCopy) {
1492: int toCopyLength = toCopy.length;
1493: char[][] result = new char[toCopyLength][];
1494: for (int i = 0; i < toCopyLength; i++) {
1495: char[] toElement = toCopy[i];
1496: int toElementLength = toElement.length;
1497: char[] resultElement = new char[toElementLength];
1498: System.arraycopy(toElement, 0, resultElement, 0,
1499: toElementLength);
1500: result[i] = resultElement;
1501: }
1502: return result;
1503: }
1504:
1505: /**
1506: * Return true if array ends with the sequence of characters contained in toBeFound,
1507: * otherwise false.
1508: * <br>
1509: * <br>
1510: * For example:
1511: * <ol>
1512: * <li><pre>
1513: * array = { 'a', 'b', 'c', 'd' }
1514: * toBeFound = { 'b', 'c' }
1515: * result => false
1516: * </pre>
1517: * </li>
1518: * <li><pre>
1519: * array = { 'a', 'b', 'c' }
1520: * toBeFound = { 'b', 'c' }
1521: * result => true
1522: * </pre>
1523: * </li>
1524: * </ol>
1525: *
1526: * @param array the array to check
1527: * @param toBeFound the array to find
1528: * @return true if array ends with the sequence of characters contained in toBeFound,
1529: * otherwise false.
1530: * @throws NullPointerException if array is null or toBeFound is null
1531: */
1532: public static final boolean endsWith(char[] array, char[] toBeFound) {
1533: int i = toBeFound.length;
1534: int j = array.length - i;
1535:
1536: if (j < 0)
1537: return false;
1538: while (--i >= 0)
1539: if (toBeFound[i] != array[i + j])
1540: return false;
1541: return true;
1542: }
1543:
1544: /**
1545: * Answers true if the two arrays are identical character by character, otherwise false.
1546: * The equality is case sensitive.
1547: * <br>
1548: * <br>
1549: * For example:
1550: * <ol>
1551: * <li><pre>
1552: * first = null
1553: * second = null
1554: * result => true
1555: * </pre>
1556: * </li>
1557: * <li><pre>
1558: * first = { { } }
1559: * second = null
1560: * result => false
1561: * </pre>
1562: * </li>
1563: * <li><pre>
1564: * first = { { 'a' } }
1565: * second = { { 'a' } }
1566: * result => true
1567: * </pre>
1568: * </li>
1569: * <li><pre>
1570: * first = { { 'A' } }
1571: * second = { { 'a' } }
1572: * result => false
1573: * </pre>
1574: * </li>
1575: * </ol>
1576: * @param first the first array
1577: * @param second the second array
1578: * @return true if the two arrays are identical character by character, otherwise false
1579: */
1580: public static final boolean equals(char[][] first, char[][] second) {
1581: if (first == second)
1582: return true;
1583: if (first == null || second == null)
1584: return false;
1585: if (first.length != second.length)
1586: return false;
1587:
1588: for (int i = first.length; --i >= 0;)
1589: if (!equals(first[i], second[i]))
1590: return false;
1591: return true;
1592: }
1593:
1594: /**
1595: * If isCaseSensite is true, answers true if the two arrays are identical character
1596: * by character, otherwise false.
1597: * If it is false, answers true if the two arrays are identical character by
1598: * character without checking the case, otherwise false.
1599: * <br>
1600: * <br>
1601: * For example:
1602: * <ol>
1603: * <li><pre>
1604: * first = null
1605: * second = null
1606: * isCaseSensitive = true
1607: * result => true
1608: * </pre>
1609: * </li>
1610: * <li><pre>
1611: * first = { { } }
1612: * second = null
1613: * isCaseSensitive = true
1614: * result => false
1615: * </pre>
1616: * </li>
1617: * <li><pre>
1618: * first = { { 'A' } }
1619: * second = { { 'a' } }
1620: * isCaseSensitive = true
1621: * result => false
1622: * </pre>
1623: * </li>
1624: * <li><pre>
1625: * first = { { 'A' } }
1626: * second = { { 'a' } }
1627: * isCaseSensitive = false
1628: * result => true
1629: * </pre>
1630: * </li>
1631: * </ol>
1632: *
1633: * @param first the first array
1634: * @param second the second array
1635: * @param isCaseSensitive check whether or not the equality should be case sensitive
1636: * @return true if the two arrays are identical character by character according to the value
1637: * of isCaseSensitive, otherwise false
1638: */
1639: public static final boolean equals(char[][] first, char[][] second,
1640: boolean isCaseSensitive) {
1641:
1642: if (isCaseSensitive) {
1643: return equals(first, second);
1644: }
1645: if (first == second)
1646: return true;
1647: if (first == null || second == null)
1648: return false;
1649: if (first.length != second.length)
1650: return false;
1651:
1652: for (int i = first.length; --i >= 0;)
1653: if (!equals(first[i], second[i], false))
1654: return false;
1655: return true;
1656: }
1657:
1658: /**
1659: * Answers true if the two arrays are identical character by character, otherwise false.
1660: * The equality is case sensitive.
1661: * <br>
1662: * <br>
1663: * For example:
1664: * <ol>
1665: * <li><pre>
1666: * first = null
1667: * second = null
1668: * result => true
1669: * </pre>
1670: * </li>
1671: * <li><pre>
1672: * first = { }
1673: * second = null
1674: * result => false
1675: * </pre>
1676: * </li>
1677: * <li><pre>
1678: * first = { 'a' }
1679: * second = { 'a' }
1680: * result => true
1681: * </pre>
1682: * </li>
1683: * <li><pre>
1684: * first = { 'a' }
1685: * second = { 'A' }
1686: * result => false
1687: * </pre>
1688: * </li>
1689: * </ol>
1690: * @param first the first array
1691: * @param second the second array
1692: * @return true if the two arrays are identical character by character, otherwise false
1693: */
1694: public static final boolean equals(char[] first, char[] second) {
1695: if (first == second)
1696: return true;
1697: if (first == null || second == null)
1698: return false;
1699: if (first.length != second.length)
1700: return false;
1701:
1702: for (int i = first.length; --i >= 0;)
1703: if (first[i] != second[i])
1704: return false;
1705: return true;
1706: }
1707:
1708: /**
1709: * Answers true if the first array is identical character by character to a portion of the second array
1710: * delimited from position secondStart (inclusive) to secondEnd(exclusive), otherwise false.
1711: * The equality is case sensitive.
1712: * <br>
1713: * <br>
1714: * For example:
1715: * <ol>
1716: * <li><pre>
1717: * first = null
1718: * second = null
1719: * secondStart = 0
1720: * secondEnd = 0
1721: * result => true
1722: * </pre>
1723: * </li>
1724: * <li><pre>
1725: * first = { }
1726: * second = null
1727: * secondStart = 0
1728: * secondEnd = 0
1729: * result => false
1730: * </pre>
1731: * </li>
1732: * <li><pre>
1733: * first = { 'a' }
1734: * second = { 'a' }
1735: * secondStart = 0
1736: * secondEnd = 1
1737: * result => true
1738: * </pre>
1739: * </li>
1740: * <li><pre>
1741: * first = { 'a' }
1742: * second = { 'A' }
1743: * secondStart = 0
1744: * secondEnd = 1
1745: * result => false
1746: * </pre>
1747: * </li>
1748: * </ol>
1749: * @param first the first array
1750: * @param second the second array
1751: * @param secondStart inclusive start position in the second array to compare
1752: * @param secondEnd exclusive end position in the second array to compare
1753: * @return true if the first array is identical character by character to fragment of second array ranging from secondStart to secondEnd-1, otherwise false
1754: * @since 3.0
1755: */
1756: public static final boolean equals(char[] first, char[] second,
1757: int secondStart, int secondEnd) {
1758: return equals(first, second, secondStart, secondEnd, true);
1759: }
1760:
1761: /**
1762: * <p>Answers true if the first array is identical character by character to a portion of the second array
1763: * delimited from position secondStart (inclusive) to secondEnd(exclusive), otherwise false. The equality could be either
1764: * case sensitive or case insensitive according to the value of the <code>isCaseSensitive</code> parameter.
1765: * </p>
1766: * <p>For example:</p>
1767: * <ol>
1768: * <li><pre>
1769: * first = null
1770: * second = null
1771: * secondStart = 0
1772: * secondEnd = 0
1773: * isCaseSensitive = false
1774: * result => true
1775: * </pre>
1776: * </li>
1777: * <li><pre>
1778: * first = { }
1779: * second = null
1780: * secondStart = 0
1781: * secondEnd = 0
1782: * isCaseSensitive = false
1783: * result => false
1784: * </pre>
1785: * </li>
1786: * <li><pre>
1787: * first = { 'a' }
1788: * second = { 'a' }
1789: * secondStart = 0
1790: * secondEnd = 1
1791: * isCaseSensitive = true
1792: * result => true
1793: * </pre>
1794: * </li>
1795: * <li><pre>
1796: * first = { 'a' }
1797: * second = { 'A' }
1798: * secondStart = 0
1799: * secondEnd = 1
1800: * isCaseSensitive = true
1801: * result => false
1802: * </pre>
1803: * </li>
1804: * <li><pre>
1805: * first = { 'a' }
1806: * second = { 'A' }
1807: * secondStart = 0
1808: * secondEnd = 1
1809: * isCaseSensitive = false
1810: * result => true
1811: * </pre>
1812: * </li>
1813: * </ol>
1814: * @param first the first array
1815: * @param second the second array
1816: * @param secondStart inclusive start position in the second array to compare
1817: * @param secondEnd exclusive end position in the second array to compare
1818: * @param isCaseSensitive check whether or not the equality should be case sensitive
1819: * @return true if the first array is identical character by character to fragment of second array ranging from secondStart to secondEnd-1, otherwise false
1820: * @since 3.2
1821: */
1822: public static final boolean equals(char[] first, char[] second,
1823: int secondStart, int secondEnd, boolean isCaseSensitive) {
1824: if (first == second)
1825: return true;
1826: if (first == null || second == null)
1827: return false;
1828: if (first.length != secondEnd - secondStart)
1829: return false;
1830: if (isCaseSensitive) {
1831: for (int i = first.length; --i >= 0;)
1832: if (first[i] != second[i + secondStart])
1833: return false;
1834: } else {
1835: for (int i = first.length; --i >= 0;)
1836: if (ScannerHelper.toLowerCase(first[i]) != ScannerHelper
1837: .toLowerCase(second[i + secondStart]))
1838: return false;
1839: }
1840: return true;
1841: }
1842:
1843: /**
1844: * If isCaseSensite is true, answers true if the two arrays are identical character
1845: * by character, otherwise false.
1846: * If it is false, answers true if the two arrays are identical character by
1847: * character without checking the case, otherwise false.
1848: * <br>
1849: * <br>
1850: * For example:
1851: * <ol>
1852: * <li><pre>
1853: * first = null
1854: * second = null
1855: * isCaseSensitive = true
1856: * result => true
1857: * </pre>
1858: * </li>
1859: * <li><pre>
1860: * first = { }
1861: * second = null
1862: * isCaseSensitive = true
1863: * result => false
1864: * </pre>
1865: * </li>
1866: * <li><pre>
1867: * first = { 'A' }
1868: * second = { 'a' }
1869: * isCaseSensitive = true
1870: * result => false
1871: * </pre>
1872: * </li>
1873: * <li><pre>
1874: * first = { 'A' }
1875: * second = { 'a' }
1876: * isCaseSensitive = false
1877: * result => true
1878: * </pre>
1879: * </li>
1880: * </ol>
1881: *
1882: * @param first the first array
1883: * @param second the second array
1884: * @param isCaseSensitive check whether or not the equality should be case sensitive
1885: * @return true if the two arrays are identical character by character according to the value
1886: * of isCaseSensitive, otherwise false
1887: */
1888: public static final boolean equals(char[] first, char[] second,
1889: boolean isCaseSensitive) {
1890:
1891: if (isCaseSensitive) {
1892: return equals(first, second);
1893: }
1894: if (first == second)
1895: return true;
1896: if (first == null || second == null)
1897: return false;
1898: if (first.length != second.length)
1899: return false;
1900:
1901: for (int i = first.length; --i >= 0;)
1902: if (ScannerHelper.toLowerCase(first[i]) != ScannerHelper
1903: .toLowerCase(second[i]))
1904: return false;
1905: return true;
1906: }
1907:
1908: /**
1909: * If isCaseSensite is true, the equality is case sensitive, otherwise it is case insensitive.
1910: *
1911: * Answers true if the name contains the fragment at the starting index startIndex, otherwise false.
1912: * <br>
1913: * <br>
1914: * For example:
1915: * <ol>
1916: * <li><pre>
1917: * fragment = { 'b', 'c' , 'd' }
1918: * name = { 'a', 'b', 'c' , 'd' }
1919: * startIndex = 1
1920: * isCaseSensitive = true
1921: * result => true
1922: * </pre>
1923: * </li>
1924: * <li><pre>
1925: * fragment = { 'b', 'c' , 'd' }
1926: * name = { 'a', 'b', 'C' , 'd' }
1927: * startIndex = 1
1928: * isCaseSensitive = true
1929: * result => false
1930: * </pre>
1931: * </li>
1932: * <li><pre>
1933: * fragment = { 'b', 'c' , 'd' }
1934: * name = { 'a', 'b', 'C' , 'd' }
1935: * startIndex = 0
1936: * isCaseSensitive = false
1937: * result => false
1938: * </pre>
1939: * </li>
1940: * <li><pre>
1941: * fragment = { 'b', 'c' , 'd' }
1942: * name = { 'a', 'b'}
1943: * startIndex = 0
1944: * isCaseSensitive = true
1945: * result => false
1946: * </pre>
1947: * </li>
1948: * </ol>
1949: *
1950: * @param fragment the fragment to check
1951: * @param name the array to check
1952: * @param startIndex the starting index
1953: * @param isCaseSensitive check whether or not the equality should be case sensitive
1954: * @return true if the name contains the fragment at the starting index startIndex according to the
1955: * value of isCaseSensitive, otherwise false.
1956: * @throws NullPointerException if fragment or name is null.
1957: */
1958: public static final boolean fragmentEquals(char[] fragment,
1959: char[] name, int startIndex, boolean isCaseSensitive) {
1960:
1961: int max = fragment.length;
1962: if (name.length < max + startIndex)
1963: return false;
1964: if (isCaseSensitive) {
1965: for (int i = max; --i >= 0;)
1966: // assumes the prefix is not larger than the name
1967: if (fragment[i] != name[i + startIndex])
1968: return false;
1969: return true;
1970: }
1971: for (int i = max; --i >= 0;)
1972: // assumes the prefix is not larger than the name
1973: if (ScannerHelper.toLowerCase(fragment[i]) != ScannerHelper
1974: .toLowerCase(name[i + startIndex]))
1975: return false;
1976: return true;
1977: }
1978:
1979: /**
1980: * Answers a hashcode for the array
1981: *
1982: * @param array the array for which a hashcode is required
1983: * @return the hashcode
1984: * @throws NullPointerException if array is null
1985: */
1986: public static final int hashCode(char[] array) {
1987: int length = array.length;
1988: int hash = length == 0 ? 31 : array[0];
1989: if (length < 8) {
1990: for (int i = length; --i > 0;)
1991: hash = (hash * 31) + array[i];
1992: } else {
1993: // 8 characters is enough to compute a decent hash code, don't waste time examining every character
1994: for (int i = length - 1, last = i > 16 ? i - 16 : 0; i > last; i -= 2)
1995: hash = (hash * 31) + array[i];
1996: }
1997: return hash & 0x7FFFFFFF;
1998: }
1999:
2000: /**
2001: * Answers true if c is a whitespace according to the JLS (\u000a, \u000c, \u000d, \u0009), otherwise false.
2002: * <br>
2003: * <br>
2004: * For example:
2005: * <ol>
2006: * <li><pre>
2007: * c = ' '
2008: * result => true
2009: * </pre>
2010: * </li>
2011: * <li><pre>
2012: * c = '\u3000'
2013: * result => false
2014: * </pre>
2015: * </li>
2016: * </ol>
2017: *
2018: * @param c the character to check
2019: * @return true if c is a whitespace according to the JLS, otherwise false.
2020: */
2021: public static boolean isWhitespace(char c) {
2022: return c < ScannerHelper.MAX_OBVIOUS
2023: && ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_JLS_SPACE) != 0);
2024: }
2025:
2026: /**
2027: * Answers the first index in the array for which the corresponding character is
2028: * equal to toBeFound. Answers -1 if no occurrence of this character is found.
2029: * <br>
2030: * <br>
2031: * For example:
2032: * <ol>
2033: * <li><pre>
2034: * toBeFound = 'c'
2035: * array = { ' a', 'b', 'c', 'd' }
2036: * result => 2
2037: * </pre>
2038: * </li>
2039: * <li><pre>
2040: * toBeFound = 'e'
2041: * array = { ' a', 'b', 'c', 'd' }
2042: * result => -1
2043: * </pre>
2044: * </li>
2045: * </ol>
2046: *
2047: * @param toBeFound the character to search
2048: * @param array the array to be searched
2049: * @return the first index in the array for which the corresponding character is
2050: * equal to toBeFound, -1 otherwise
2051: * @throws NullPointerException if array is null
2052: */
2053: public static final int indexOf(char toBeFound, char[] array) {
2054: return indexOf(toBeFound, array, 0);
2055: }
2056:
2057: /**
2058: * Answers the first index in the array for which the toBeFound array is a matching
2059: * subarray following the case rule. Answers -1 if no match is found.
2060: * <br>
2061: * <br>
2062: * For example:
2063: * <ol>
2064: * <li><pre>
2065: * toBeFound = { 'c' }
2066: * array = { ' a', 'b', 'c', 'd' }
2067: * result => 2
2068: * </pre>
2069: * </li>
2070: * <li><pre>
2071: * toBeFound = { 'e' }
2072: * array = { ' a', 'b', 'c', 'd' }
2073: * result => -1
2074: * </pre>
2075: * </li>
2076: * </ol>
2077: *
2078: * @param toBeFound the subarray to search
2079: * @param array the array to be searched
2080: * @param isCaseSensitive flag to know if the matching should be case sensitive
2081: * @return the first index in the array for which the toBeFound array is a matching
2082: * subarray following the case rule, -1 otherwise
2083: * @throws NullPointerException if array is null or toBeFound is null
2084: * @since 3.2
2085: */
2086: public static final int indexOf(char[] toBeFound, char[] array,
2087: boolean isCaseSensitive) {
2088: return indexOf(toBeFound, array, isCaseSensitive, 0);
2089: }
2090:
2091: /**
2092: * Answers the first index in the array for which the toBeFound array is a matching
2093: * subarray following the case rule starting at the index start. Answers -1 if no match is found.
2094: * <br>
2095: * <br>
2096: * For example:
2097: * <ol>
2098: * <li><pre>
2099: * toBeFound = { 'c' }
2100: * array = { ' a', 'b', 'c', 'd' }
2101: * result => 2
2102: * </pre>
2103: * </li>
2104: * <li><pre>
2105: * toBeFound = { 'e' }
2106: * array = { ' a', 'b', 'c', 'd' }
2107: * result => -1
2108: * </pre>
2109: * </li>
2110: * </ol>
2111: *
2112: * @param toBeFound the subarray to search
2113: * @param array the array to be searched
2114: * @param isCaseSensitive flag to know if the matching should be case sensitive
2115: * @param start the starting index
2116: * @return the first index in the array for which the toBeFound array is a matching
2117: * subarray following the case rule starting at the index start, -1 otherwise
2118: * @throws NullPointerException if array is null or toBeFound is null
2119: * @since 3.2
2120: */
2121: public static final int indexOf(final char[] toBeFound,
2122: final char[] array, final boolean isCaseSensitive,
2123: final int start) {
2124: return indexOf(toBeFound, array, isCaseSensitive, start,
2125: array.length);
2126: }
2127:
2128: /**
2129: * Answers the first index in the array for which the toBeFound array is a matching
2130: * subarray following the case rule starting at the index start. Answers -1 if no match is found.
2131: * <br>
2132: * <br>
2133: * For example:
2134: * <ol>
2135: * <li><pre>
2136: * toBeFound = { 'c' }
2137: * array = { ' a', 'b', 'c', 'd' }
2138: * result => 2
2139: * </pre>
2140: * </li>
2141: * <li><pre>
2142: * toBeFound = { 'e' }
2143: * array = { ' a', 'b', 'c', 'd' }
2144: * result => -1
2145: * </pre>
2146: * </li>
2147: * </ol>
2148: *
2149: * @param toBeFound the subarray to search
2150: * @param array the array to be searched
2151: * @param isCaseSensitive flag to know if the matching should be case sensitive
2152: * @param start the starting index (inclusive)
2153: * @param end the end index (exclusive)
2154: * @return the first index in the array for which the toBeFound array is a matching
2155: * subarray following the case rule starting at the index start, -1 otherwise
2156: * @throws NullPointerException if array is null or toBeFound is null
2157: * @since 3.2
2158: */
2159: public static final int indexOf(final char[] toBeFound,
2160: final char[] array, final boolean isCaseSensitive,
2161: final int start, final int end) {
2162: final int arrayLength = end;
2163: final int toBeFoundLength = toBeFound.length;
2164: if (toBeFoundLength > arrayLength)
2165: return -1;
2166: if (toBeFoundLength == 0)
2167: return 0;
2168: if (toBeFoundLength == arrayLength) {
2169: if (isCaseSensitive) {
2170: for (int i = start; i < arrayLength; i++) {
2171: if (array[i] != toBeFound[i])
2172: return -1;
2173: }
2174: return 0;
2175: } else {
2176: for (int i = start; i < arrayLength; i++) {
2177: if (ScannerHelper.toLowerCase(array[i]) != ScannerHelper
2178: .toLowerCase(toBeFound[i]))
2179: return -1;
2180: }
2181: return 0;
2182: }
2183: }
2184: if (isCaseSensitive) {
2185: arrayLoop: for (int i = start, max = arrayLength
2186: - toBeFoundLength + 1; i < max; i++) {
2187: if (array[i] == toBeFound[0]) {
2188: for (int j = 1; j < toBeFoundLength; j++) {
2189: if (array[i + j] != toBeFound[j])
2190: continue arrayLoop;
2191: }
2192: return i;
2193: }
2194: }
2195: } else {
2196: arrayLoop: for (int i = start, max = arrayLength
2197: - toBeFoundLength + 1; i < max; i++) {
2198: if (ScannerHelper.toLowerCase(array[i]) == ScannerHelper
2199: .toLowerCase(toBeFound[0])) {
2200: for (int j = 1; j < toBeFoundLength; j++) {
2201: if (ScannerHelper.toLowerCase(array[i + j]) != ScannerHelper
2202: .toLowerCase(toBeFound[j]))
2203: continue arrayLoop;
2204: }
2205: return i;
2206: }
2207: }
2208: }
2209: return -1;
2210: }
2211:
2212: /**
2213: * Answers the first index in the array for which the corresponding character is
2214: * equal to toBeFound starting the search at index start.
2215: * Answers -1 if no occurrence of this character is found.
2216: * <br>
2217: * <br>
2218: * For example:
2219: * <ol>
2220: * <li><pre>
2221: * toBeFound = 'c'
2222: * array = { ' a', 'b', 'c', 'd' }
2223: * start = 2
2224: * result => 2
2225: * </pre>
2226: * </li>
2227: * <li><pre>
2228: * toBeFound = 'c'
2229: * array = { ' a', 'b', 'c', 'd' }
2230: * start = 3
2231: * result => -1
2232: * </pre>
2233: * </li>
2234: * <li><pre>
2235: * toBeFound = 'e'
2236: * array = { ' a', 'b', 'c', 'd' }
2237: * start = 1
2238: * result => -1
2239: * </pre>
2240: * </li>
2241: * </ol>
2242: *
2243: * @param toBeFound the character to search
2244: * @param array the array to be searched
2245: * @param start the starting index
2246: * @return the first index in the array for which the corresponding character is
2247: * equal to toBeFound, -1 otherwise
2248: * @throws NullPointerException if array is null
2249: * @throws ArrayIndexOutOfBoundsException if start is lower than 0
2250: */
2251: public static final int indexOf(char toBeFound, char[] array,
2252: int start) {
2253: for (int i = start; i < array.length; i++)
2254: if (toBeFound == array[i])
2255: return i;
2256: return -1;
2257: }
2258:
2259: /**
2260: * Answers the first index in the array for which the corresponding character is
2261: * equal to toBeFound starting the search at index start and before the ending index.
2262: * Answers -1 if no occurrence of this character is found.
2263: * <br>
2264: * <br>
2265: * For example:
2266: * <ol>
2267: * <li><pre>
2268: * toBeFound = 'c'
2269: * array = { ' a', 'b', 'c', 'd' }
2270: * start = 2
2271: * result => 2
2272: * </pre>
2273: * </li>
2274: * <li><pre>
2275: * toBeFound = 'c'
2276: * array = { ' a', 'b', 'c', 'd' }
2277: * start = 3
2278: * result => -1
2279: * </pre>
2280: * </li>
2281: * <li><pre>
2282: * toBeFound = 'e'
2283: * array = { ' a', 'b', 'c', 'd' }
2284: * start = 1
2285: * result => -1
2286: * </pre>
2287: * </li>
2288: * </ol>
2289: *
2290: * @param toBeFound the character to search
2291: * @param array the array to be searched
2292: * @param start the starting index (inclusive)
2293: * @param end the ending index (exclusive)
2294: * @return the first index in the array for which the corresponding character is
2295: * equal to toBeFound, -1 otherwise
2296: * @throws NullPointerException if array is null
2297: * @throws ArrayIndexOutOfBoundsException if start is lower than 0 or ending greater than array length
2298: * @since 3.2
2299: */
2300: public static final int indexOf(char toBeFound, char[] array,
2301: int start, int end) {
2302: for (int i = start; i < end; i++)
2303: if (toBeFound == array[i])
2304: return i;
2305: return -1;
2306: }
2307:
2308: /**
2309: * Answers the last index in the array for which the corresponding character is
2310: * equal to toBeFound starting from the end of the array.
2311: * Answers -1 if no occurrence of this character is found.
2312: * <br>
2313: * <br>
2314: * For example:
2315: * <ol>
2316: * <li><pre>
2317: * toBeFound = 'c'
2318: * array = { ' a', 'b', 'c', 'd' , 'c', 'e' }
2319: * result => 4
2320: * </pre>
2321: * </li>
2322: * <li><pre>
2323: * toBeFound = 'e'
2324: * array = { ' a', 'b', 'c', 'd' }
2325: * result => -1
2326: * </pre>
2327: * </li>
2328: * </ol>
2329: *
2330: * @param toBeFound the character to search
2331: * @param array the array to be searched
2332: * @return the last index in the array for which the corresponding character is
2333: * equal to toBeFound starting from the end of the array, -1 otherwise
2334: * @throws NullPointerException if array is null
2335: */
2336: public static final int lastIndexOf(char toBeFound, char[] array) {
2337: for (int i = array.length; --i >= 0;)
2338: if (toBeFound == array[i])
2339: return i;
2340: return -1;
2341: }
2342:
2343: /**
2344: * Answers the last index in the array for which the corresponding character is
2345: * equal to toBeFound stopping at the index startIndex.
2346: * Answers -1 if no occurrence of this character is found.
2347: * <br>
2348: * <br>
2349: * For example:
2350: * <ol>
2351: * <li><pre>
2352: * toBeFound = 'c'
2353: * array = { ' a', 'b', 'c', 'd' }
2354: * startIndex = 2
2355: * result => 2
2356: * </pre>
2357: * </li>
2358: * <li><pre>
2359: * toBeFound = 'c'
2360: * array = { ' a', 'b', 'c', 'd', 'e' }
2361: * startIndex = 3
2362: * result => -1
2363: * </pre>
2364: * </li>
2365: * <li><pre>
2366: * toBeFound = 'e'
2367: * array = { ' a', 'b', 'c', 'd' }
2368: * startIndex = 0
2369: * result => -1
2370: * </pre>
2371: * </li>
2372: * </ol>
2373: *
2374: * @param toBeFound the character to search
2375: * @param array the array to be searched
2376: * @param startIndex the stopping index
2377: * @return the last index in the array for which the corresponding character is
2378: * equal to toBeFound stopping at the index startIndex, -1 otherwise
2379: * @throws NullPointerException if array is null
2380: * @throws ArrayIndexOutOfBoundsException if startIndex is lower than 0
2381: */
2382: public static final int lastIndexOf(char toBeFound, char[] array,
2383: int startIndex) {
2384: for (int i = array.length; --i >= startIndex;)
2385: if (toBeFound == array[i])
2386: return i;
2387: return -1;
2388: }
2389:
2390: /**
2391: * Answers the last index in the array for which the corresponding character is
2392: * equal to toBeFound starting from endIndex to startIndex.
2393: * Answers -1 if no occurrence of this character is found.
2394: * <br>
2395: * <br>
2396: * For example:
2397: * <ol>
2398: * <li><pre>
2399: * toBeFound = 'c'
2400: * array = { ' a', 'b', 'c', 'd' }
2401: * startIndex = 2
2402: * endIndex = 2
2403: * result => 2
2404: * </pre>
2405: * </li>
2406: * <li><pre>
2407: * toBeFound = 'c'
2408: * array = { ' a', 'b', 'c', 'd', 'e' }
2409: * startIndex = 3
2410: * endIndex = 4
2411: * result => -1
2412: * </pre>
2413: * </li>
2414: * <li><pre>
2415: * toBeFound = 'e'
2416: * array = { ' a', 'b', 'c', 'd' }
2417: * startIndex = 0
2418: * endIndex = 3
2419: * result => -1
2420: * </pre>
2421: * </li>
2422: * </ol>
2423: *
2424: * @param toBeFound the character to search
2425: * @param array the array to be searched
2426: * @param startIndex the stopping index
2427: * @param endIndex the starting index
2428: * @return the last index in the array for which the corresponding character is
2429: * equal to toBeFound starting from endIndex to startIndex, -1 otherwise
2430: * @throws NullPointerException if array is null
2431: * @throws ArrayIndexOutOfBoundsException if endIndex is greater or equals to array length or starting is lower than 0
2432: */
2433: public static final int lastIndexOf(char toBeFound, char[] array,
2434: int startIndex, int endIndex) {
2435: for (int i = endIndex; --i >= startIndex;)
2436: if (toBeFound == array[i])
2437: return i;
2438: return -1;
2439: }
2440:
2441: /**
2442: * Answers the last portion of a name given a separator.
2443: * <br>
2444: * <br>
2445: * For example,
2446: * <pre>
2447: * lastSegment("java.lang.Object".toCharArray(),'.') --> Object
2448: * </pre>
2449: *
2450: * @param array the array
2451: * @param separator the given separator
2452: * @return the last portion of a name given a separator
2453: * @throws NullPointerException if array is null
2454: */
2455: final static public char[] lastSegment(char[] array, char separator) {
2456: int pos = lastIndexOf(separator, array);
2457: if (pos < 0)
2458: return array;
2459: return subarray(array, pos + 1, array.length);
2460: }
2461:
2462: /**
2463: * Answers true if the pattern matches the given name, false otherwise. This char[] pattern matching
2464: * accepts wild-cards '*' and '?'.
2465: *
2466: * When not case sensitive, the pattern is assumed to already be lowercased, the
2467: * name will be lowercased character per character as comparing.
2468: * If name is null, the answer is false.
2469: * If pattern is null, the answer is true if name is not null.
2470: * <br>
2471: * <br>
2472: * For example:
2473: * <ol>
2474: * <li><pre>
2475: * pattern = { '?', 'b', '*' }
2476: * name = { 'a', 'b', 'c' , 'd' }
2477: * isCaseSensitive = true
2478: * result => true
2479: * </pre>
2480: * </li>
2481: * <li><pre>
2482: * pattern = { '?', 'b', '?' }
2483: * name = { 'a', 'b', 'c' , 'd' }
2484: * isCaseSensitive = true
2485: * result => false
2486: * </pre>
2487: * </li>
2488: * <li><pre>
2489: * pattern = { 'b', '*' }
2490: * name = { 'a', 'b', 'c' , 'd' }
2491: * isCaseSensitive = true
2492: * result => false
2493: * </pre>
2494: * </li>
2495: * </ol>
2496: *
2497: * @param pattern the given pattern
2498: * @param name the given name
2499: * @param isCaseSensitive flag to know whether or not the matching should be case sensitive
2500: * @return true if the pattern matches the given name, false otherwise
2501: */
2502: public static final boolean match(char[] pattern, char[] name,
2503: boolean isCaseSensitive) {
2504:
2505: if (name == null)
2506: return false; // null name cannot match
2507: if (pattern == null)
2508: return true; // null pattern is equivalent to '*'
2509:
2510: return match(pattern, 0, pattern.length, name, 0, name.length,
2511: isCaseSensitive);
2512: }
2513:
2514: /**
2515: * Answers true if a sub-pattern matches the subpart of the given name, false otherwise.
2516: * char[] pattern matching, accepting wild-cards '*' and '?'. Can match only subset of name/pattern.
2517: * end positions are non-inclusive.
2518: * The subpattern is defined by the patternStart and pattternEnd positions.
2519: * When not case sensitive, the pattern is assumed to already be lowercased, the
2520: * name will be lowercased character per character as comparing.
2521: * <br>
2522: * <br>
2523: * For example:
2524: * <ol>
2525: * <li><pre>
2526: * pattern = { '?', 'b', '*' }
2527: * patternStart = 1
2528: * patternEnd = 3
2529: * name = { 'a', 'b', 'c' , 'd' }
2530: * nameStart = 1
2531: * nameEnd = 4
2532: * isCaseSensitive = true
2533: * result => true
2534: * </pre>
2535: * </li>
2536: * <li><pre>
2537: * pattern = { '?', 'b', '*' }
2538: * patternStart = 1
2539: * patternEnd = 2
2540: * name = { 'a', 'b', 'c' , 'd' }
2541: * nameStart = 1
2542: * nameEnd = 2
2543: * isCaseSensitive = true
2544: * result => false
2545: * </pre>
2546: * </li>
2547: * </ol>
2548: *
2549: * @param pattern the given pattern
2550: * @param patternStart the given pattern start
2551: * @param patternEnd the given pattern end
2552: * @param name the given name
2553: * @param nameStart the given name start
2554: * @param nameEnd the given name end
2555: * @param isCaseSensitive flag to know if the matching should be case sensitive
2556: * @return true if a sub-pattern matches the subpart of the given name, false otherwise
2557: */
2558: public static final boolean match(char[] pattern, int patternStart,
2559: int patternEnd, char[] name, int nameStart, int nameEnd,
2560: boolean isCaseSensitive) {
2561:
2562: if (name == null)
2563: return false; // null name cannot match
2564: if (pattern == null)
2565: return true; // null pattern is equivalent to '*'
2566: int iPattern = patternStart;
2567: int iName = nameStart;
2568:
2569: if (patternEnd < 0)
2570: patternEnd = pattern.length;
2571: if (nameEnd < 0)
2572: nameEnd = name.length;
2573:
2574: /* check first segment */
2575: char patternChar = 0;
2576: while ((iPattern < patternEnd)
2577: && (patternChar = pattern[iPattern]) != '*') {
2578: if (iName == nameEnd)
2579: return false;
2580: if (patternChar != (isCaseSensitive ? name[iName]
2581: : ScannerHelper.toLowerCase(name[iName]))
2582: && patternChar != '?') {
2583: return false;
2584: }
2585: iName++;
2586: iPattern++;
2587: }
2588: /* check sequence of star+segment */
2589: int segmentStart;
2590: if (patternChar == '*') {
2591: segmentStart = ++iPattern; // skip star
2592: } else {
2593: segmentStart = 0; // force iName check
2594: }
2595: int prefixStart = iName;
2596: checkSegment: while (iName < nameEnd) {
2597: if (iPattern == patternEnd) {
2598: iPattern = segmentStart; // mismatch - restart current segment
2599: iName = ++prefixStart;
2600: continue checkSegment;
2601: }
2602: /* segment is ending */
2603: if ((patternChar = pattern[iPattern]) == '*') {
2604: segmentStart = ++iPattern; // skip start
2605: if (segmentStart == patternEnd) {
2606: return true;
2607: }
2608: prefixStart = iName;
2609: continue checkSegment;
2610: }
2611: /* check current name character */
2612: if ((isCaseSensitive ? name[iName] : ScannerHelper
2613: .toLowerCase(name[iName])) != patternChar
2614: && patternChar != '?') {
2615: iPattern = segmentStart; // mismatch - restart current segment
2616: iName = ++prefixStart;
2617: continue checkSegment;
2618: }
2619: iName++;
2620: iPattern++;
2621: }
2622:
2623: return (segmentStart == patternEnd)
2624: || (iName == nameEnd && iPattern == patternEnd)
2625: || (iPattern == patternEnd - 1 && pattern[iPattern] == '*');
2626: }
2627:
2628: /**
2629: * Answers true if the pattern matches the filepath using the pathSepatator, false otherwise.
2630: *
2631: * Path char[] pattern matching, accepting wild-cards '**', '*' and '?' (using Ant directory tasks
2632: * conventions, also see "http://jakarta.apache.org/ant/manual/dirtasks.html#defaultexcludes").
2633: * Path pattern matching is enhancing regular pattern matching in supporting extra rule where '**' represent
2634: * any folder combination.
2635: * Special rule:
2636: * - foo\ is equivalent to foo\**
2637: * When not case sensitive, the pattern is assumed to already be lowercased, the
2638: * name will be lowercased character per character as comparing.
2639: *
2640: * @param pattern the given pattern
2641: * @param filepath the given path
2642: * @param isCaseSensitive to find out whether or not the matching should be case sensitive
2643: * @param pathSeparator the given path separator
2644: * @return true if the pattern matches the filepath using the pathSepatator, false otherwise
2645: */
2646: public static final boolean pathMatch(char[] pattern,
2647: char[] filepath, boolean isCaseSensitive, char pathSeparator) {
2648:
2649: if (filepath == null)
2650: return false; // null name cannot match
2651: if (pattern == null)
2652: return true; // null pattern is equivalent to '*'
2653:
2654: // offsets inside pattern
2655: int pSegmentStart = pattern[0] == pathSeparator ? 1 : 0;
2656: int pLength = pattern.length;
2657: int pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
2658: pSegmentStart + 1);
2659: if (pSegmentEnd < 0)
2660: pSegmentEnd = pLength;
2661:
2662: // special case: pattern foo\ is equivalent to foo\**
2663: boolean freeTrailingDoubleStar = pattern[pLength - 1] == pathSeparator;
2664:
2665: // offsets inside filepath
2666: int fSegmentStart, fLength = filepath.length;
2667: if (filepath[0] != pathSeparator) {
2668: fSegmentStart = 0;
2669: } else {
2670: fSegmentStart = 1;
2671: }
2672: if (fSegmentStart != pSegmentStart) {
2673: return false; // both must start with a separator or none.
2674: }
2675: int fSegmentEnd = CharOperation.indexOf(pathSeparator,
2676: filepath, fSegmentStart + 1);
2677: if (fSegmentEnd < 0)
2678: fSegmentEnd = fLength;
2679:
2680: // first segments
2681: while (pSegmentStart < pLength
2682: && !(pSegmentEnd == pLength && freeTrailingDoubleStar || (pSegmentEnd == pSegmentStart + 2
2683: && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*'))) {
2684:
2685: if (fSegmentStart >= fLength)
2686: return false;
2687: if (!CharOperation.match(pattern, pSegmentStart,
2688: pSegmentEnd, filepath, fSegmentStart, fSegmentEnd,
2689: isCaseSensitive)) {
2690: return false;
2691: }
2692:
2693: // jump to next segment
2694: pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
2695: pSegmentStart = pSegmentEnd + 1);
2696: // skip separator
2697: if (pSegmentEnd < 0)
2698: pSegmentEnd = pLength;
2699:
2700: fSegmentEnd = CharOperation.indexOf(pathSeparator,
2701: filepath, fSegmentStart = fSegmentEnd + 1);
2702: // skip separator
2703: if (fSegmentEnd < 0)
2704: fSegmentEnd = fLength;
2705: }
2706:
2707: /* check sequence of doubleStar+segment */
2708: int pSegmentRestart;
2709: if ((pSegmentStart >= pLength && freeTrailingDoubleStar)
2710: || (pSegmentEnd == pSegmentStart + 2
2711: && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*')) {
2712: pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
2713: pSegmentStart = pSegmentEnd + 1);
2714: // skip separator
2715: if (pSegmentEnd < 0)
2716: pSegmentEnd = pLength;
2717: pSegmentRestart = pSegmentStart;
2718: } else {
2719: if (pSegmentStart >= pLength)
2720: return fSegmentStart >= fLength; // true if filepath is done too.
2721: pSegmentRestart = 0; // force fSegmentStart check
2722: }
2723: int fSegmentRestart = fSegmentStart;
2724: checkSegment: while (fSegmentStart < fLength) {
2725:
2726: if (pSegmentStart >= pLength) {
2727: if (freeTrailingDoubleStar)
2728: return true;
2729: // mismatch - restart current path segment
2730: pSegmentEnd = CharOperation.indexOf(pathSeparator,
2731: pattern, pSegmentStart = pSegmentRestart);
2732: if (pSegmentEnd < 0)
2733: pSegmentEnd = pLength;
2734:
2735: fSegmentRestart = CharOperation.indexOf(pathSeparator,
2736: filepath, fSegmentRestart + 1);
2737: // skip separator
2738: if (fSegmentRestart < 0) {
2739: fSegmentRestart = fLength;
2740: } else {
2741: fSegmentRestart++;
2742: }
2743: fSegmentEnd = CharOperation.indexOf(pathSeparator,
2744: filepath, fSegmentStart = fSegmentRestart);
2745: if (fSegmentEnd < 0)
2746: fSegmentEnd = fLength;
2747: continue checkSegment;
2748: }
2749:
2750: /* path segment is ending */
2751: if (pSegmentEnd == pSegmentStart + 2
2752: && pattern[pSegmentStart] == '*'
2753: && pattern[pSegmentStart + 1] == '*') {
2754: pSegmentEnd = CharOperation.indexOf(pathSeparator,
2755: pattern, pSegmentStart = pSegmentEnd + 1);
2756: // skip separator
2757: if (pSegmentEnd < 0)
2758: pSegmentEnd = pLength;
2759: pSegmentRestart = pSegmentStart;
2760: fSegmentRestart = fSegmentStart;
2761: if (pSegmentStart >= pLength)
2762: return true;
2763: continue checkSegment;
2764: }
2765: /* chech current path segment */
2766: if (!CharOperation.match(pattern, pSegmentStart,
2767: pSegmentEnd, filepath, fSegmentStart, fSegmentEnd,
2768: isCaseSensitive)) {
2769: // mismatch - restart current path segment
2770: pSegmentEnd = CharOperation.indexOf(pathSeparator,
2771: pattern, pSegmentStart = pSegmentRestart);
2772: if (pSegmentEnd < 0)
2773: pSegmentEnd = pLength;
2774:
2775: fSegmentRestart = CharOperation.indexOf(pathSeparator,
2776: filepath, fSegmentRestart + 1);
2777: // skip separator
2778: if (fSegmentRestart < 0) {
2779: fSegmentRestart = fLength;
2780: } else {
2781: fSegmentRestart++;
2782: }
2783: fSegmentEnd = CharOperation.indexOf(pathSeparator,
2784: filepath, fSegmentStart = fSegmentRestart);
2785: if (fSegmentEnd < 0)
2786: fSegmentEnd = fLength;
2787: continue checkSegment;
2788: }
2789: // jump to next segment
2790: pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
2791: pSegmentStart = pSegmentEnd + 1);
2792: // skip separator
2793: if (pSegmentEnd < 0)
2794: pSegmentEnd = pLength;
2795:
2796: fSegmentEnd = CharOperation.indexOf(pathSeparator,
2797: filepath, fSegmentStart = fSegmentEnd + 1);
2798: // skip separator
2799: if (fSegmentEnd < 0)
2800: fSegmentEnd = fLength;
2801: }
2802:
2803: return (pSegmentRestart >= pSegmentEnd)
2804: || (fSegmentStart >= fLength && pSegmentStart >= pLength)
2805: || (pSegmentStart == pLength - 2
2806: && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*')
2807: || (pSegmentStart == pLength && freeTrailingDoubleStar);
2808: }
2809:
2810: /**
2811: * Answers the number of occurrences of the given character in the given array, 0 if any.
2812: *
2813: * <br>
2814: * <br>
2815: * For example:
2816: * <ol>
2817: * <li><pre>
2818: * toBeFound = 'b'
2819: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2820: * result => 3
2821: * </pre>
2822: * </li>
2823: * <li><pre>
2824: * toBeFound = 'c'
2825: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2826: * result => 0
2827: * </pre>
2828: * </li>
2829: * </ol>
2830: *
2831: * @param toBeFound the given character
2832: * @param array the given array
2833: * @return the number of occurrences of the given character in the given array, 0 if any
2834: * @throws NullPointerException if array is null
2835: */
2836: public static final int occurencesOf(char toBeFound, char[] array) {
2837: int count = 0;
2838: for (int i = 0; i < array.length; i++)
2839: if (toBeFound == array[i])
2840: count++;
2841: return count;
2842: }
2843:
2844: /**
2845: * Answers the number of occurrences of the given character in the given array starting
2846: * at the given index, 0 if any.
2847: *
2848: * <br>
2849: * <br>
2850: * For example:
2851: * <ol>
2852: * <li><pre>
2853: * toBeFound = 'b'
2854: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2855: * start = 2
2856: * result => 2
2857: * </pre>
2858: * </li>
2859: * <li><pre>
2860: * toBeFound = 'c'
2861: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2862: * start = 0
2863: * result => 0
2864: * </pre>
2865: * </li>
2866: * </ol>
2867: *
2868: * @param toBeFound the given character
2869: * @param array the given array
2870: * @param start the given index
2871: * @return the number of occurrences of the given character in the given array, 0 if any
2872: * @throws NullPointerException if array is null
2873: * @throws ArrayIndexOutOfBoundsException if start is lower than 0
2874: */
2875: public static final int occurencesOf(char toBeFound, char[] array,
2876: int start) {
2877: int count = 0;
2878: for (int i = start; i < array.length; i++)
2879: if (toBeFound == array[i])
2880: count++;
2881: return count;
2882: }
2883:
2884: /**
2885: * Answers true if the given name starts with the given prefix, false otherwise.
2886: * The comparison is case sensitive.
2887: * <br>
2888: * <br>
2889: * For example:
2890: * <ol>
2891: * <li><pre>
2892: * prefix = { 'a' , 'b' }
2893: * name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2894: * result => true
2895: * </pre>
2896: * </li>
2897: * <li><pre>
2898: * prefix = { 'a' , 'c' }
2899: * name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2900: * result => false
2901: * </pre>
2902: * </li>
2903: * </ol>
2904: *
2905: * @param prefix the given prefix
2906: * @param name the given name
2907: * @return true if the given name starts with the given prefix, false otherwise
2908: * @throws NullPointerException if the given name is null or if the given prefix is null
2909: */
2910: public static final boolean prefixEquals(char[] prefix, char[] name) {
2911:
2912: int max = prefix.length;
2913: if (name.length < max)
2914: return false;
2915: for (int i = max; --i >= 0;)
2916: // assumes the prefix is not larger than the name
2917: if (prefix[i] != name[i])
2918: return false;
2919: return true;
2920: }
2921:
2922: /**
2923: * Answers true if the given name starts with the given prefix, false otherwise.
2924: * isCaseSensitive is used to find out whether or not the comparison should be case sensitive.
2925: * <br>
2926: * <br>
2927: * For example:
2928: * <ol>
2929: * <li><pre>
2930: * prefix = { 'a' , 'B' }
2931: * name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2932: * isCaseSensitive = false
2933: * result => true
2934: * </pre>
2935: * </li>
2936: * <li><pre>
2937: * prefix = { 'a' , 'B' }
2938: * name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2939: * isCaseSensitive = true
2940: * result => false
2941: * </pre>
2942: * </li>
2943: * </ol>
2944: *
2945: * @param prefix the given prefix
2946: * @param name the given name
2947: * @param isCaseSensitive to find out whether or not the comparison should be case sensitive
2948: * @return true if the given name starts with the given prefix, false otherwise
2949: * @throws NullPointerException if the given name is null or if the given prefix is null
2950: */
2951: public static final boolean prefixEquals(char[] prefix,
2952: char[] name, boolean isCaseSensitive) {
2953:
2954: int max = prefix.length;
2955: if (name.length < max)
2956: return false;
2957: if (isCaseSensitive) {
2958: for (int i = max; --i >= 0;)
2959: // assumes the prefix is not larger than the name
2960: if (prefix[i] != name[i])
2961: return false;
2962: return true;
2963: }
2964:
2965: for (int i = max; --i >= 0;)
2966: // assumes the prefix is not larger than the name
2967: if (ScannerHelper.toLowerCase(prefix[i]) != ScannerHelper
2968: .toLowerCase(name[i]))
2969: return false;
2970: return true;
2971: }
2972:
2973: /**
2974: * Answers a new array removing a given character. Answers the given array if there is
2975: * no occurrence of the character to remove.
2976: * <br>
2977: * <br>
2978: * For example:
2979: * <ol>
2980: * <li><pre>
2981: * array = { 'a' , 'b', 'b', 'c', 'b', 'a' }
2982: * toBeRemoved = 'b'
2983: * return { 'a' , 'c', 'a' }
2984: * </pre>
2985: * </li>
2986: * <li><pre>
2987: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
2988: * toBeRemoved = 'c'
2989: * return array
2990: * </pre>
2991: * </li>
2992: * </ol>
2993: *
2994: * @param array the given array
2995: * @param toBeRemoved the character to be removed
2996: * @return a new array removing given character
2997: * @since 3.2
2998: */
2999: public static final char[] remove(char[] array, char toBeRemoved) {
3000:
3001: if (array == null)
3002: return null;
3003: int length = array.length;
3004: if (length == 0)
3005: return array;
3006: char[] result = null;
3007: int count = 0;
3008: for (int i = 0; i < length; i++) {
3009: char c = array[i];
3010: if (c == toBeRemoved) {
3011: if (result == null) {
3012: result = new char[length];
3013: System.arraycopy(array, 0, result, 0, i);
3014: count = i;
3015: }
3016: } else if (result != null) {
3017: result[count++] = c;
3018: }
3019: }
3020: if (result == null)
3021: return array;
3022: System.arraycopy(result, 0, result = new char[count], 0, count);
3023: return result;
3024: }
3025:
3026: /**
3027: * Replace all occurrence of the character to be replaced with the replacement character in the
3028: * given array.
3029: * <br>
3030: * <br>
3031: * For example:
3032: * <ol>
3033: * <li><pre>
3034: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
3035: * toBeReplaced = 'b'
3036: * replacementChar = 'a'
3037: * result => No returned value, but array is now equals to { 'a' , 'a', 'a', 'a', 'a', 'a' }
3038: * </pre>
3039: * </li>
3040: * <li><pre>
3041: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
3042: * toBeReplaced = 'c'
3043: * replacementChar = 'a'
3044: * result => No returned value, but array is now equals to { 'a' , 'b', 'b', 'a', 'b', 'a' }
3045: * </pre>
3046: * </li>
3047: * </ol>
3048: *
3049: * @param array the given array
3050: * @param toBeReplaced the character to be replaced
3051: * @param replacementChar the replacement character
3052: * @throws NullPointerException if the given array is null
3053: */
3054: public static final void replace(char[] array, char toBeReplaced,
3055: char replacementChar) {
3056: if (toBeReplaced != replacementChar) {
3057: for (int i = 0, max = array.length; i < max; i++) {
3058: if (array[i] == toBeReplaced)
3059: array[i] = replacementChar;
3060: }
3061: }
3062: }
3063:
3064: /**
3065: * Replace all occurrences of characters to be replaced with the replacement character in the
3066: * given array.
3067: * <br>
3068: * <br>
3069: * For example:
3070: * <ol>
3071: * <li><pre>
3072: * array = { 'a' , 'b', 'b', 'c', 'a', 'b', 'c', 'a' }
3073: * toBeReplaced = { 'b', 'c' }
3074: * replacementChar = 'a'
3075: * result => No returned value, but array is now equals to { 'a' , 'a', 'a', 'a', 'a', 'a', 'a', 'a' }
3076: * </pre>
3077: * </li>
3078: * </ol>
3079: *
3080: * @param array the given array
3081: * @param toBeReplaced characters to be replaced
3082: * @param replacementChar the replacement character
3083: * @throws NullPointerException if arrays are null.
3084: * @since 3.1
3085: */
3086: public static final void replace(char[] array, char[] toBeReplaced,
3087: char replacementChar) {
3088: replace(array, toBeReplaced, replacementChar, 0, array.length);
3089: }
3090:
3091: /**
3092: * Replace all occurrences of characters to be replaced with the replacement character in the
3093: * given array from the start position (inclusive) to the end position (exclusive).
3094: * <br>
3095: * <br>
3096: * For example:
3097: * <ol>
3098: * <li><pre>
3099: * array = { 'a' , 'b', 'b', 'c', 'a', 'b', 'c', 'a' }
3100: * toBeReplaced = { 'b', 'c' }
3101: * replacementChar = 'a'
3102: * start = 4
3103: * end = 8
3104: * result => No returned value, but array is now equals to { 'a' , 'b', 'b', 'c', 'a', 'a', 'a', 'a' }
3105: * </pre>
3106: * </li>
3107: * </ol>
3108: *
3109: * @param array the given array
3110: * @param toBeReplaced characters to be replaced
3111: * @param replacementChar the replacement character
3112: * @param start the given start position (inclusive)
3113: * @param end the given end position (exclusive)
3114: * @throws NullPointerException if arrays are null.
3115: * @since 3.2
3116: */
3117: public static final void replace(char[] array, char[] toBeReplaced,
3118: char replacementChar, int start, int end) {
3119: for (int i = end; --i >= start;)
3120: for (int j = toBeReplaced.length; --j >= 0;)
3121: if (array[i] == toBeReplaced[j])
3122: array[i] = replacementChar;
3123: }
3124:
3125: /**
3126: * Answers a new array of characters with substitutions. No side-effect is operated on the original
3127: * array, in case no substitution happened, then the result is the same as the
3128: * original one.
3129: * <br>
3130: * <br>
3131: * For example:
3132: * <ol>
3133: * <li><pre>
3134: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
3135: * toBeReplaced = { 'b' }
3136: * replacementChar = { 'a', 'a' }
3137: * result => { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }
3138: * </pre>
3139: * </li>
3140: * <li><pre>
3141: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
3142: * toBeReplaced = { 'c' }
3143: * replacementChar = { 'a' }
3144: * result => { 'a' , 'b', 'b', 'a', 'b', 'a' }
3145: * </pre>
3146: * </li>
3147: * </ol>
3148: *
3149: * @param array the given array
3150: * @param toBeReplaced characters to be replaced
3151: * @param replacementChars the replacement characters
3152: * @return a new array of characters with substitutions or the given array if none
3153: * @throws NullPointerException if the given array is null
3154: */
3155: public static final char[] replace(char[] array,
3156: char[] toBeReplaced, char[] replacementChars) {
3157:
3158: int max = array.length;
3159: int replacedLength = toBeReplaced.length;
3160: int replacementLength = replacementChars.length;
3161:
3162: int[] starts = new int[5];
3163: int occurrenceCount = 0;
3164:
3165: if (!equals(toBeReplaced, replacementChars)) {
3166:
3167: next: for (int i = 0; i < max;) {
3168: int index = indexOf(toBeReplaced, array, true, i);
3169: if (index == -1) {
3170: i++;
3171: continue next;
3172: }
3173: if (occurrenceCount == starts.length) {
3174: System.arraycopy(starts, 0,
3175: starts = new int[occurrenceCount * 2], 0,
3176: occurrenceCount);
3177: }
3178: starts[occurrenceCount++] = index;
3179: i = index + replacedLength;
3180: }
3181: }
3182: if (occurrenceCount == 0)
3183: return array;
3184: char[] result = new char[max + occurrenceCount
3185: * (replacementLength - replacedLength)];
3186: int inStart = 0, outStart = 0;
3187: for (int i = 0; i < occurrenceCount; i++) {
3188: int offset = starts[i] - inStart;
3189: System.arraycopy(array, inStart, result, outStart, offset);
3190: inStart += offset;
3191: outStart += offset;
3192: System.arraycopy(replacementChars, 0, result, outStart,
3193: replacementLength);
3194: inStart += replacedLength;
3195: outStart += replacementLength;
3196: }
3197: System.arraycopy(array, inStart, result, outStart, max
3198: - inStart);
3199: return result;
3200: }
3201:
3202: /**
3203: * Replace all occurrence of the character to be replaced with the replacement character
3204: * in a copy of the given array. Returns the given array if no occurrences of the character
3205: * to be replaced are found.
3206: * <br>
3207: * <br>
3208: * For example:
3209: * <ol>
3210: * <li><pre>
3211: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
3212: * toBeReplaced = 'b'
3213: * replacementChar = 'a'
3214: * result => A new array that is equals to { 'a' , 'a', 'a', 'a', 'a', 'a' }
3215: * </pre>
3216: * </li>
3217: * <li><pre>
3218: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
3219: * toBeReplaced = 'c'
3220: * replacementChar = 'a'
3221: * result => The original array that remains unchanged.
3222: * </pre>
3223: * </li>
3224: * </ol>
3225: *
3226: * @param array the given array
3227: * @param toBeReplaced the character to be replaced
3228: * @param replacementChar the replacement character
3229: * @throws NullPointerException if the given array is null
3230: * @since 3.1
3231: */
3232: public static final char[] replaceOnCopy(char[] array,
3233: char toBeReplaced, char replacementChar) {
3234:
3235: char[] result = null;
3236: for (int i = 0, length = array.length; i < length; i++) {
3237: char c = array[i];
3238: if (c == toBeReplaced) {
3239: if (result == null) {
3240: result = new char[length];
3241: System.arraycopy(array, 0, result, 0, i);
3242: }
3243: result[i] = replacementChar;
3244: } else if (result != null) {
3245: result[i] = c;
3246: }
3247: }
3248: if (result == null)
3249: return array;
3250: return result;
3251: }
3252:
3253: /**
3254: * Return a new array which is the split of the given array using the given divider and trimming each subarray to remove
3255: * whitespaces equals to ' '.
3256: * <br>
3257: * <br>
3258: * For example:
3259: * <ol>
3260: * <li><pre>
3261: * divider = 'b'
3262: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
3263: * result => { { 'a' }, { }, { 'a' }, { 'a' } }
3264: * </pre>
3265: * </li>
3266: * <li><pre>
3267: * divider = 'c'
3268: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
3269: * result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
3270: * </pre>
3271: * </li>
3272: * <li><pre>
3273: * divider = 'b'
3274: * array = { 'a' , ' ', 'b', 'b', 'a', 'b', 'a' }
3275: * result => { { 'a' }, { }, { 'a' }, { 'a' } }
3276: * </pre>
3277: * </li>
3278: * <li><pre>
3279: * divider = 'c'
3280: * array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' }
3281: * result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
3282: * </pre>
3283: * </li>
3284: * </ol>
3285: *
3286: * @param divider the given divider
3287: * @param array the given array
3288: * @return a new array which is the split of the given array using the given divider and trimming each subarray to remove
3289: * whitespaces equals to ' '
3290: */
3291: public static final char[][] splitAndTrimOn(char divider,
3292: char[] array) {
3293: int length = array == null ? 0 : array.length;
3294: if (length == 0)
3295: return NO_CHAR_CHAR;
3296:
3297: int wordCount = 1;
3298: for (int i = 0; i < length; i++)
3299: if (array[i] == divider)
3300: wordCount++;
3301: char[][] split = new char[wordCount][];
3302: int last = 0, currentWord = 0;
3303: for (int i = 0; i < length; i++) {
3304: if (array[i] == divider) {
3305: int start = last, end = i - 1;
3306: while (start < i && array[start] == ' ')
3307: start++;
3308: while (end > start && array[end] == ' ')
3309: end--;
3310: split[currentWord] = new char[end - start + 1];
3311: System.arraycopy(array, start, split[currentWord++], 0,
3312: end - start + 1);
3313: last = i + 1;
3314: }
3315: }
3316: int start = last, end = length - 1;
3317: while (start < length && array[start] == ' ')
3318: start++;
3319: while (end > start && array[end] == ' ')
3320: end--;
3321: split[currentWord] = new char[end - start + 1];
3322: System.arraycopy(array, start, split[currentWord++], 0, end
3323: - start + 1);
3324: return split;
3325: }
3326:
3327: /**
3328: * Return a new array which is the split of the given array using the given divider.
3329: * <br>
3330: * <br>
3331: * For example:
3332: * <ol>
3333: * <li><pre>
3334: * divider = 'b'
3335: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
3336: * result => { { 'a' }, { }, { 'a' }, { 'a' } }
3337: * </pre>
3338: * </li>
3339: * <li><pre>
3340: * divider = 'c'
3341: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
3342: * result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
3343: * </pre>
3344: * </li>
3345: * <li><pre>
3346: * divider = 'c'
3347: * array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' }
3348: * result => { { ' ', 'a', 'b', 'b', 'a', 'b', 'a', ' ' } }
3349: * </pre>
3350: * </li>
3351: * </ol>
3352: *
3353: * @param divider the given divider
3354: * @param array the given array
3355: * @return a new array which is the split of the given array using the given divider
3356: */
3357: public static final char[][] splitOn(char divider, char[] array) {
3358: int length = array == null ? 0 : array.length;
3359: if (length == 0)
3360: return NO_CHAR_CHAR;
3361:
3362: int wordCount = 1;
3363: for (int i = 0; i < length; i++)
3364: if (array[i] == divider)
3365: wordCount++;
3366: char[][] split = new char[wordCount][];
3367: int last = 0, currentWord = 0;
3368: for (int i = 0; i < length; i++) {
3369: if (array[i] == divider) {
3370: split[currentWord] = new char[i - last];
3371: System.arraycopy(array, last, split[currentWord++], 0,
3372: i - last);
3373: last = i + 1;
3374: }
3375: }
3376: split[currentWord] = new char[length - last];
3377: System.arraycopy(array, last, split[currentWord], 0, length
3378: - last);
3379: return split;
3380: }
3381:
3382: /**
3383: * Return a new array which is the split of the given array using the given divider. The given end
3384: * is exclusive and the given start is inclusive.
3385: * <br>
3386: * <br>
3387: * For example:
3388: * <ol>
3389: * <li><pre>
3390: * divider = 'b'
3391: * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
3392: * start = 2
3393: * end = 5
3394: * result => { { }, { 'a' }, { } }
3395: * </pre>
3396: * </li>
3397: * </ol>
3398: *
3399: * @param divider the given divider
3400: * @param array the given array
3401: * @param start the given starting index
3402: * @param end the given ending index
3403: * @return a new array which is the split of the given array using the given divider
3404: * @throws ArrayIndexOutOfBoundsException if start is lower than 0 or end is greater than the array length
3405: */
3406: public static final char[][] splitOn(char divider, char[] array,
3407: int start, int end) {
3408: int length = array == null ? 0 : array.length;
3409: if (length == 0 || start > end)
3410: return NO_CHAR_CHAR;
3411:
3412: int wordCount = 1;
3413: for (int i = start; i < end; i++)
3414: if (array[i] == divider)
3415: wordCount++;
3416: char[][] split = new char[wordCount][];
3417: int last = start, currentWord = 0;
3418: for (int i = start; i < end; i++) {
3419: if (array[i] == divider) {
3420: split[currentWord] = new char[i - last];
3421: System.arraycopy(array, last, split[currentWord++], 0,
3422: i - last);
3423: last = i + 1;
3424: }
3425: }
3426: split[currentWord] = new char[end - last];
3427: System
3428: .arraycopy(array, last, split[currentWord], 0, end
3429: - last);
3430: return split;
3431: }
3432:
3433: /**
3434: * Answers a new array which is a copy of the given array starting at the given start and
3435: * ending at the given end. The given start is inclusive and the given end is exclusive.
3436: * Answers null if start is greater than end, if start is lower than 0 or if end is greater
3437: * than the length of the given array. If end equals -1, it is converted to the array length.
3438: * <br>
3439: * <br>
3440: * For example:
3441: * <ol>
3442: * <li><pre>
3443: * array = { { 'a' } , { 'b' } }
3444: * start = 0
3445: * end = 1
3446: * result => { { 'a' } }
3447: * </pre>
3448: * </li>
3449: * <li><pre>
3450: * array = { { 'a' } , { 'b' } }
3451: * start = 0
3452: * end = -1
3453: * result => { { 'a' }, { 'b' } }
3454: * </pre>
3455: * </li>
3456: * </ol>
3457: *
3458: * @param array the given array
3459: * @param start the given starting index
3460: * @param end the given ending index
3461: * @return a new array which is a copy of the given array starting at the given start and
3462: * ending at the given end
3463: * @throws NullPointerException if the given array is null
3464: */
3465: public static final char[][] subarray(char[][] array, int start,
3466: int end) {
3467: if (end == -1)
3468: end = array.length;
3469: if (start > end)
3470: return null;
3471: if (start < 0)
3472: return null;
3473: if (end > array.length)
3474: return null;
3475:
3476: char[][] result = new char[end - start][];
3477: System.arraycopy(array, start, result, 0, end - start);
3478: return result;
3479: }
3480:
3481: /**
3482: * Answers a new array which is a copy of the given array starting at the given start and
3483: * ending at the given end. The given start is inclusive and the given end is exclusive.
3484: * Answers null if start is greater than end, if start is lower than 0 or if end is greater
3485: * than the length of the given array. If end equals -1, it is converted to the array length.
3486: * <br>
3487: * <br>
3488: * For example:
3489: * <ol>
3490: * <li><pre>
3491: * array = { 'a' , 'b' }
3492: * start = 0
3493: * end = 1
3494: * result => { 'a' }
3495: * </pre>
3496: * </li>
3497: * <li><pre>
3498: * array = { 'a', 'b' }
3499: * start = 0
3500: * end = -1
3501: * result => { 'a' , 'b' }
3502: * </pre>
3503: * </li>
3504: * </ol>
3505: *
3506: * @param array the given array
3507: * @param start the given starting index
3508: * @param end the given ending index
3509: * @return a new array which is a copy of the given array starting at the given start and
3510: * ending at the given end
3511: * @throws NullPointerException if the given array is null
3512: */
3513: public static final char[] subarray(char[] array, int start, int end) {
3514: if (end == -1)
3515: end = array.length;
3516: if (start > end)
3517: return null;
3518: if (start < 0)
3519: return null;
3520: if (end > array.length)
3521: return null;
3522:
3523: char[] result = new char[end - start];
3524: System.arraycopy(array, start, result, 0, end - start);
3525: return result;
3526: }
3527:
3528: /**
3529: * Answers the result of a char[] conversion to lowercase. Answers null if the given chars array is null.
3530: * <br>
3531: * NOTE: If no conversion was necessary, then answers back the argument one.
3532: * <br>
3533: * <br>
3534: * For example:
3535: * <ol>
3536: * <li><pre>
3537: * chars = { 'a' , 'b' }
3538: * result => { 'a' , 'b' }
3539: * </pre>
3540: * </li>
3541: * <li><pre>
3542: * array = { 'A', 'b' }
3543: * result => { 'a' , 'b' }
3544: * </pre>
3545: * </li>
3546: * </ol>
3547: *
3548: * @param chars the chars to convert
3549: * @return the result of a char[] conversion to lowercase
3550: */
3551: final static public char[] toLowerCase(char[] chars) {
3552: if (chars == null)
3553: return null;
3554: int length = chars.length;
3555: char[] lowerChars = null;
3556: for (int i = 0; i < length; i++) {
3557: char c = chars[i];
3558: char lc = ScannerHelper.toLowerCase(c);
3559: if ((c != lc) || (lowerChars != null)) {
3560: if (lowerChars == null) {
3561: System.arraycopy(chars, 0,
3562: lowerChars = new char[length], 0, i);
3563: }
3564: lowerChars[i] = lc;
3565: }
3566: }
3567: return lowerChars == null ? chars : lowerChars;
3568: }
3569:
3570: /**
3571: * Answers a new array removing leading and trailing spaces (' '). Answers the given array if there is no
3572: * space characters to remove.
3573: * <br>
3574: * <br>
3575: * For example:
3576: * <ol>
3577: * <li><pre>
3578: * chars = { ' ', 'a' , 'b', ' ', ' ' }
3579: * result => { 'a' , 'b' }
3580: * </pre>
3581: * </li>
3582: * <li><pre>
3583: * array = { 'A', 'b' }
3584: * result => { 'A' , 'b' }
3585: * </pre>
3586: * </li>
3587: * </ol>
3588: *
3589: * @param chars the given array
3590: * @return a new array removing leading and trailing spaces (' ')
3591: */
3592: final static public char[] trim(char[] chars) {
3593:
3594: if (chars == null)
3595: return null;
3596:
3597: int start = 0, length = chars.length, end = length - 1;
3598: while (start < length && chars[start] == ' ') {
3599: start++;
3600: }
3601: while (end > start && chars[end] == ' ') {
3602: end--;
3603: }
3604: if (start != 0 || end != length - 1) {
3605: return subarray(chars, start, end + 1);
3606: }
3607: return chars;
3608: }
3609:
3610: /**
3611: * Answers a string which is the concatenation of the given array using the '.' as a separator.
3612: * <br>
3613: * <br>
3614: * For example:
3615: * <ol>
3616: * <li><pre>
3617: * array = { { 'a' } , { 'b' } }
3618: * result => "a.b"
3619: * </pre>
3620: * </li>
3621: * <li><pre>
3622: * array = { { ' ', 'a' } , { 'b' } }
3623: * result => " a.b"
3624: * </pre>
3625: * </li>
3626: * </ol>
3627: *
3628: * @param array the given array
3629: * @return a string which is the concatenation of the given array using the '.' as a separator
3630: */
3631: final static public String toString(char[][] array) {
3632: char[] result = concatWith(array, '.');
3633: return new String(result);
3634: }
3635:
3636: /**
3637: * Answers an array of strings from the given array of char array.
3638: *
3639: * @param array the given array
3640: * @return an array of strings
3641: * @since 3.0
3642: */
3643: final static public String[] toStrings(char[][] array) {
3644: if (array == null)
3645: return NO_STRINGS;
3646: int length = array.length;
3647: if (length == 0)
3648: return NO_STRINGS;
3649: String[] result = new String[length];
3650: for (int i = 0; i < length; i++)
3651: result[i] = new String(array[i]);
3652: return result;
3653: }
3654: }
|