0001: /*
0002: * Copyright 2002-2007 the original author or authors.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016:
0017: package org.springframework.util;
0018:
0019: import java.util.ArrayList;
0020: import java.util.Arrays;
0021: import java.util.Collection;
0022: import java.util.Collections;
0023: import java.util.Enumeration;
0024: import java.util.Iterator;
0025: import java.util.LinkedList;
0026: import java.util.List;
0027: import java.util.Locale;
0028: import java.util.Properties;
0029: import java.util.Set;
0030: import java.util.StringTokenizer;
0031: import java.util.TreeSet;
0032:
0033: /**
0034: * Miscellaneous {@link String} utility methods.
0035: *
0036: * <p>Mainly for internal use within the framework; consider
0037: * <a href="http://jakarta.apache.org/commons/lang/">Jakarta's Commons Lang</a>
0038: * for a more comprehensive suite of
0039: * {@link org.apache.commons.lang.StringUtils String utilities}.
0040: *
0041: * <p>This class delivers some simple functionality that should really
0042: * be provided by the core Java <code>String</code> and {@link StringBuffer}
0043: * classes, such as the ability to {@link #replace} all occurrences of a given
0044: * substring in a target string. It also provides easy-to-use methods to
0045: * convert between delimited strings, such as CSV strings, and collections and
0046: * arrays.
0047: *
0048: * @author Rod Johnson
0049: * @author Juergen Hoeller
0050: * @author Keith Donald
0051: * @author Rob Harrop
0052: * @author Rick Evans
0053: * @since 16 April 2001
0054: */
0055: public abstract class StringUtils {
0056:
0057: private static final String FOLDER_SEPARATOR = "/";
0058:
0059: private static final String WINDOWS_FOLDER_SEPARATOR = "\\";
0060:
0061: private static final String TOP_PATH = "..";
0062:
0063: private static final String CURRENT_PATH = ".";
0064:
0065: private static final char EXTENSION_SEPARATOR = '.';
0066:
0067: //---------------------------------------------------------------------
0068: // General convenience methods for working with Strings
0069: //---------------------------------------------------------------------
0070:
0071: /**
0072: * Check that the given String is neither <code>null</code> nor of length 0.
0073: * Note: Will return <code>true</code> for a String that purely consists of whitespace.
0074: * <p><pre>
0075: * StringUtils.hasLength(null) = false
0076: * StringUtils.hasLength("") = false
0077: * StringUtils.hasLength(" ") = true
0078: * StringUtils.hasLength("Hello") = true
0079: * </pre>
0080: * @param str the String to check (may be <code>null</code>)
0081: * @return <code>true</code> if the String is not null and has length
0082: * @see #hasText(String)
0083: */
0084: public static boolean hasLength(String str) {
0085: return (str != null && str.length() > 0);
0086: }
0087:
0088: /**
0089: * Check whether the given String has actual text.
0090: * More specifically, returns <code>true</code> if the string not <code>null</code>,
0091: * its length is greater than 0, and it contains at least one non-whitespace character.
0092: * <p><pre>
0093: * StringUtils.hasText(null) = false
0094: * StringUtils.hasText("") = false
0095: * StringUtils.hasText(" ") = false
0096: * StringUtils.hasText("12345") = true
0097: * StringUtils.hasText(" 12345 ") = true
0098: * </pre>
0099: * @param str the String to check (may be <code>null</code>)
0100: * @return <code>true</code> if the String is not <code>null</code>, its length is
0101: * greater than 0, and it does not contain whitespace only
0102: * @see java.lang.Character#isWhitespace
0103: */
0104: public static boolean hasText(String str) {
0105: if (!hasLength(str)) {
0106: return false;
0107: }
0108: int strLen = str.length();
0109: for (int i = 0; i < strLen; i++) {
0110: if (!Character.isWhitespace(str.charAt(i))) {
0111: return true;
0112: }
0113: }
0114: return false;
0115: }
0116:
0117: /**
0118: * Check whether the given String contains any whitespace characters.
0119: * @param str the String to check (may be <code>null</code>)
0120: * @return <code>true</code> if the String is not empty and
0121: * contains at least 1 whitespace character
0122: * @see java.lang.Character#isWhitespace
0123: */
0124: public static boolean containsWhitespace(String str) {
0125: if (!hasLength(str)) {
0126: return false;
0127: }
0128: int strLen = str.length();
0129: for (int i = 0; i < strLen; i++) {
0130: if (Character.isWhitespace(str.charAt(i))) {
0131: return true;
0132: }
0133: }
0134: return false;
0135: }
0136:
0137: /**
0138: * Trim leading and trailing whitespace from the given String.
0139: * @param str the String to check
0140: * @return the trimmed String
0141: * @see java.lang.Character#isWhitespace
0142: */
0143: public static String trimWhitespace(String str) {
0144: if (!hasLength(str)) {
0145: return str;
0146: }
0147: StringBuffer buf = new StringBuffer(str);
0148: while (buf.length() > 0
0149: && Character.isWhitespace(buf.charAt(0))) {
0150: buf.deleteCharAt(0);
0151: }
0152: while (buf.length() > 0
0153: && Character.isWhitespace(buf.charAt(buf.length() - 1))) {
0154: buf.deleteCharAt(buf.length() - 1);
0155: }
0156: return buf.toString();
0157: }
0158:
0159: /**
0160: * Trim <i>all</i> whitespace from the given String:
0161: * leading, trailing, and inbetween characters.
0162: * @param str the String to check
0163: * @return the trimmed String
0164: * @see java.lang.Character#isWhitespace
0165: */
0166: public static String trimAllWhitespace(String str) {
0167: if (!hasLength(str)) {
0168: return str;
0169: }
0170: StringBuffer buf = new StringBuffer(str);
0171: int index = 0;
0172: while (buf.length() > index) {
0173: if (Character.isWhitespace(buf.charAt(index))) {
0174: buf.deleteCharAt(index);
0175: } else {
0176: index++;
0177: }
0178: }
0179: return buf.toString();
0180: }
0181:
0182: /**
0183: * Trim leading whitespace from the given String.
0184: * @param str the String to check
0185: * @return the trimmed String
0186: * @see java.lang.Character#isWhitespace
0187: */
0188: public static String trimLeadingWhitespace(String str) {
0189: if (!hasLength(str)) {
0190: return str;
0191: }
0192: StringBuffer buf = new StringBuffer(str);
0193: while (buf.length() > 0
0194: && Character.isWhitespace(buf.charAt(0))) {
0195: buf.deleteCharAt(0);
0196: }
0197: return buf.toString();
0198: }
0199:
0200: /**
0201: * Trim trailing whitespace from the given String.
0202: * @param str the String to check
0203: * @return the trimmed String
0204: * @see java.lang.Character#isWhitespace
0205: */
0206: public static String trimTrailingWhitespace(String str) {
0207: if (!hasLength(str)) {
0208: return str;
0209: }
0210: StringBuffer buf = new StringBuffer(str);
0211: while (buf.length() > 0
0212: && Character.isWhitespace(buf.charAt(buf.length() - 1))) {
0213: buf.deleteCharAt(buf.length() - 1);
0214: }
0215: return buf.toString();
0216: }
0217:
0218: /**
0219: * Trim all occurences of the supplied leading character from the given String.
0220: * @param str the String to check
0221: * @param leadingCharacter the leading character to be trimmed
0222: * @return the trimmed String
0223: */
0224: public static String trimLeadingCharacter(String str,
0225: char leadingCharacter) {
0226: if (!hasLength(str)) {
0227: return str;
0228: }
0229: StringBuffer buf = new StringBuffer(str);
0230: while (buf.length() > 0 && buf.charAt(0) == leadingCharacter) {
0231: buf.deleteCharAt(0);
0232: }
0233: return buf.toString();
0234: }
0235:
0236: /**
0237: * Trim all occurences of the supplied trailing character from the given String.
0238: * @param str the String to check
0239: * @param trailingCharacter the trailing character to be trimmed
0240: * @return the trimmed String
0241: */
0242: public static String trimTrailingCharacter(String str,
0243: char trailingCharacter) {
0244: if (!hasLength(str)) {
0245: return str;
0246: }
0247: StringBuffer buf = new StringBuffer(str);
0248: while (buf.length() > 0
0249: && buf.charAt(buf.length() - 1) == trailingCharacter) {
0250: buf.deleteCharAt(buf.length() - 1);
0251: }
0252: return buf.toString();
0253: }
0254:
0255: /**
0256: * Test if the given String starts with the specified prefix,
0257: * ignoring upper/lower case.
0258: * @param str the String to check
0259: * @param prefix the prefix to look for
0260: * @see java.lang.String#startsWith
0261: */
0262: public static boolean startsWithIgnoreCase(String str, String prefix) {
0263: if (str == null || prefix == null) {
0264: return false;
0265: }
0266: if (str.startsWith(prefix)) {
0267: return true;
0268: }
0269: if (str.length() < prefix.length()) {
0270: return false;
0271: }
0272: String lcStr = str.substring(0, prefix.length()).toLowerCase();
0273: String lcPrefix = prefix.toLowerCase();
0274: return lcStr.equals(lcPrefix);
0275: }
0276:
0277: /**
0278: * Test if the given String ends with the specified suffix,
0279: * ignoring upper/lower case.
0280: * @param str the String to check
0281: * @param suffix the suffix to look for
0282: * @see java.lang.String#endsWith
0283: */
0284: public static boolean endsWithIgnoreCase(String str, String suffix) {
0285: if (str == null || suffix == null) {
0286: return false;
0287: }
0288: if (str.endsWith(suffix)) {
0289: return true;
0290: }
0291: if (str.length() < suffix.length()) {
0292: return false;
0293: }
0294:
0295: String lcStr = str.substring(str.length() - suffix.length())
0296: .toLowerCase();
0297: String lcSuffix = suffix.toLowerCase();
0298: return lcStr.equals(lcSuffix);
0299: }
0300:
0301: /**
0302: * Count the occurrences of the substring in string s.
0303: * @param str string to search in. Return 0 if this is null.
0304: * @param sub string to search for. Return 0 if this is null.
0305: */
0306: public static int countOccurrencesOf(String str, String sub) {
0307: if (str == null || sub == null || str.length() == 0
0308: || sub.length() == 0) {
0309: return 0;
0310: }
0311: int count = 0, pos = 0, idx = 0;
0312: while ((idx = str.indexOf(sub, pos)) != -1) {
0313: ++count;
0314: pos = idx + sub.length();
0315: }
0316: return count;
0317: }
0318:
0319: /**
0320: * Replace all occurences of a substring within a string with
0321: * another string.
0322: * @param inString String to examine
0323: * @param oldPattern String to replace
0324: * @param newPattern String to insert
0325: * @return a String with the replacements
0326: */
0327: public static String replace(String inString, String oldPattern,
0328: String newPattern) {
0329: if (inString == null) {
0330: return null;
0331: }
0332: if (oldPattern == null || newPattern == null) {
0333: return inString;
0334: }
0335:
0336: StringBuffer sbuf = new StringBuffer();
0337: // output StringBuffer we'll build up
0338: int pos = 0; // our position in the old string
0339: int index = inString.indexOf(oldPattern);
0340: // the index of an occurrence we've found, or -1
0341: int patLen = oldPattern.length();
0342: while (index >= 0) {
0343: sbuf.append(inString.substring(pos, index));
0344: sbuf.append(newPattern);
0345: pos = index + patLen;
0346: index = inString.indexOf(oldPattern, pos);
0347: }
0348: sbuf.append(inString.substring(pos));
0349:
0350: // remember to append any characters to the right of a match
0351: return sbuf.toString();
0352: }
0353:
0354: /**
0355: * Delete all occurrences of the given substring.
0356: * @param inString the original String
0357: * @param pattern the pattern to delete all occurrences of
0358: * @return the resulting String
0359: */
0360: public static String delete(String inString, String pattern) {
0361: return replace(inString, pattern, "");
0362: }
0363:
0364: /**
0365: * Delete any character in a given String.
0366: * @param inString the original String
0367: * @param charsToDelete a set of characters to delete.
0368: * E.g. "az\n" will delete 'a's, 'z's and new lines.
0369: * @return the resulting String
0370: */
0371: public static String deleteAny(String inString, String charsToDelete) {
0372: if (!hasLength(inString) || !hasLength(charsToDelete)) {
0373: return inString;
0374: }
0375: StringBuffer out = new StringBuffer();
0376: for (int i = 0; i < inString.length(); i++) {
0377: char c = inString.charAt(i);
0378: if (charsToDelete.indexOf(c) == -1) {
0379: out.append(c);
0380: }
0381: }
0382: return out.toString();
0383: }
0384:
0385: //---------------------------------------------------------------------
0386: // Convenience methods for working with formatted Strings
0387: //---------------------------------------------------------------------
0388:
0389: /**
0390: * Quote the given String with single quotes.
0391: * @param str the input String (e.g. "myString")
0392: * @return the quoted String (e.g. "'myString'"),
0393: * or <code>null<code> if the input was <code>null</code>
0394: */
0395: public static String quote(String str) {
0396: return (str != null ? "'" + str + "'" : null);
0397: }
0398:
0399: /**
0400: * Turn the given Object into a String with single quotes
0401: * if it is a String; keeping the Object as-is else.
0402: * @param obj the input Object (e.g. "myString")
0403: * @return the quoted String (e.g. "'myString'"),
0404: * or the input object as-is if not a String
0405: */
0406: public static Object quoteIfString(Object obj) {
0407: return (obj instanceof String ? quote((String) obj) : obj);
0408: }
0409:
0410: /**
0411: * Unqualify a string qualified by a '.' dot character. For example,
0412: * "this.name.is.qualified", returns "qualified".
0413: * @param qualifiedName the qualified name
0414: */
0415: public static String unqualify(String qualifiedName) {
0416: return unqualify(qualifiedName, '.');
0417: }
0418:
0419: /**
0420: * Unqualify a string qualified by a separator character. For example,
0421: * "this:name:is:qualified" returns "qualified" if using a ':' separator.
0422: * @param qualifiedName the qualified name
0423: * @param separator the separator
0424: */
0425: public static String unqualify(String qualifiedName, char separator) {
0426: return qualifiedName.substring(qualifiedName
0427: .lastIndexOf(separator) + 1);
0428: }
0429:
0430: /**
0431: * Capitalize a <code>String</code>, changing the first letter to
0432: * upper case as per {@link Character#toUpperCase(char)}.
0433: * No other letters are changed.
0434: * @param str the String to capitalize, may be <code>null</code>
0435: * @return the capitalized String, <code>null</code> if null
0436: */
0437: public static String capitalize(String str) {
0438: return changeFirstCharacterCase(str, true);
0439: }
0440:
0441: /**
0442: * Uncapitalize a <code>String</code>, changing the first letter to
0443: * lower case as per {@link Character#toLowerCase(char)}.
0444: * No other letters are changed.
0445: * @param str the String to uncapitalize, may be <code>null</code>
0446: * @return the uncapitalized String, <code>null</code> if null
0447: */
0448: public static String uncapitalize(String str) {
0449: return changeFirstCharacterCase(str, false);
0450: }
0451:
0452: private static String changeFirstCharacterCase(String str,
0453: boolean capitalize) {
0454: if (str == null || str.length() == 0) {
0455: return str;
0456: }
0457: StringBuffer buf = new StringBuffer(str.length());
0458: if (capitalize) {
0459: buf.append(Character.toUpperCase(str.charAt(0)));
0460: } else {
0461: buf.append(Character.toLowerCase(str.charAt(0)));
0462: }
0463: buf.append(str.substring(1));
0464: return buf.toString();
0465: }
0466:
0467: /**
0468: * Extract the filename from the given path,
0469: * e.g. "mypath/myfile.txt" -> "myfile.txt".
0470: * @param path the file path (may be <code>null</code>)
0471: * @return the extracted filename, or <code>null</code> if none
0472: */
0473: public static String getFilename(String path) {
0474: if (path == null) {
0475: return null;
0476: }
0477: int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR);
0478: return (separatorIndex != -1 ? path
0479: .substring(separatorIndex + 1) : path);
0480: }
0481:
0482: /**
0483: * Extract the filename extension from the given path,
0484: * e.g. "mypath/myfile.txt" -> "txt".
0485: * @param path the file path (may be <code>null</code>)
0486: * @return the extracted filename extension, or <code>null</code> if none
0487: */
0488: public static String getFilenameExtension(String path) {
0489: if (path == null) {
0490: return null;
0491: }
0492: int sepIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
0493: return (sepIndex != -1 ? path.substring(sepIndex + 1) : null);
0494: }
0495:
0496: /**
0497: * Strip the filename extension from the given path,
0498: * e.g. "mypath/myfile.txt" -> "mypath/myfile".
0499: * @param path the file path (may be <code>null</code>)
0500: * @return the path with stripped filename extension,
0501: * or <code>null</code> if none
0502: */
0503: public static String stripFilenameExtension(String path) {
0504: if (path == null) {
0505: return null;
0506: }
0507: int sepIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
0508: return (sepIndex != -1 ? path.substring(0, sepIndex) : path);
0509: }
0510:
0511: /**
0512: * Apply the given relative path to the given path,
0513: * assuming standard Java folder separation (i.e. "/" separators);
0514: * @param path the path to start from (usually a full file path)
0515: * @param relativePath the relative path to apply
0516: * (relative to the full file path above)
0517: * @return the full file path that results from applying the relative path
0518: */
0519: public static String applyRelativePath(String path,
0520: String relativePath) {
0521: int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR);
0522: if (separatorIndex != -1) {
0523: String newPath = path.substring(0, separatorIndex);
0524: if (!relativePath.startsWith(FOLDER_SEPARATOR)) {
0525: newPath += FOLDER_SEPARATOR;
0526: }
0527: return newPath + relativePath;
0528: } else {
0529: return relativePath;
0530: }
0531: }
0532:
0533: /**
0534: * Normalize the path by suppressing sequences like "path/.." and
0535: * inner simple dots.
0536: * <p>The result is convenient for path comparison. For other uses,
0537: * notice that Windows separators ("\") are replaced by simple slashes.
0538: * @param path the original path
0539: * @return the normalized path
0540: */
0541: public static String cleanPath(String path) {
0542: String pathToUse = replace(path, WINDOWS_FOLDER_SEPARATOR,
0543: FOLDER_SEPARATOR);
0544:
0545: // Strip prefix from path to analyze, to not treat it as part of the
0546: // first path element. This is necessary to correctly parse paths like
0547: // "file:core/../core/io/Resource.class", where the ".." should just
0548: // strip the first "core" directory while keeping the "file:" prefix.
0549: int prefixIndex = pathToUse.indexOf(":");
0550: String prefix = "";
0551: if (prefixIndex != -1) {
0552: prefix = pathToUse.substring(0, prefixIndex + 1);
0553: pathToUse = pathToUse.substring(prefixIndex + 1);
0554: }
0555:
0556: String[] pathArray = delimitedListToStringArray(pathToUse,
0557: FOLDER_SEPARATOR);
0558: List pathElements = new LinkedList();
0559: int tops = 0;
0560:
0561: for (int i = pathArray.length - 1; i >= 0; i--) {
0562: if (CURRENT_PATH.equals(pathArray[i])) {
0563: // Points to current directory - drop it.
0564: } else if (TOP_PATH.equals(pathArray[i])) {
0565: // Registering top path found.
0566: tops++;
0567: } else {
0568: if (tops > 0) {
0569: // Merging path element with corresponding to top path.
0570: tops--;
0571: } else {
0572: // Normal path element found.
0573: pathElements.add(0, pathArray[i]);
0574: }
0575: }
0576: }
0577:
0578: // Remaining top paths need to be retained.
0579: for (int i = 0; i < tops; i++) {
0580: pathElements.add(0, TOP_PATH);
0581: }
0582:
0583: return prefix
0584: + collectionToDelimitedString(pathElements,
0585: FOLDER_SEPARATOR);
0586: }
0587:
0588: /**
0589: * Compare two paths after normalization of them.
0590: * @param path1 first path for comparison
0591: * @param path2 second path for comparison
0592: * @return whether the two paths are equivalent after normalization
0593: */
0594: public static boolean pathEquals(String path1, String path2) {
0595: return cleanPath(path1).equals(cleanPath(path2));
0596: }
0597:
0598: /**
0599: * Parse the given <code>localeString</code> into a {@link Locale}.
0600: * <p>This is the inverse operation of {@link Locale#toString Locale's toString}.
0601: * @param localeString the locale string, following <code>Locale's</code>
0602: * <code>toString()</code> format ("en", "en_UK", etc);
0603: * also accepts spaces as separators, as an alternative to underscores
0604: * @return a corresponding <code>Locale</code> instance
0605: */
0606: public static Locale parseLocaleString(String localeString) {
0607: String[] parts = tokenizeToStringArray(localeString, "_ ",
0608: false, false);
0609: String language = (parts.length > 0 ? parts[0] : "");
0610: String country = (parts.length > 1 ? parts[1] : "");
0611: String variant = "";
0612: if (parts.length >= 2) {
0613: // There is definitely a variant, and it is everything after the country
0614: // code sans the separator between the country code and the variant.
0615: int endIndexOfCountryCode = localeString.indexOf(country)
0616: + country.length();
0617: // Strip off any leading '_' and whitespace, what's left is the variant.
0618: variant = trimLeadingWhitespace(localeString
0619: .substring(endIndexOfCountryCode));
0620: if (variant.startsWith("_")) {
0621: variant = trimLeadingCharacter(variant, '_');
0622: }
0623: }
0624: return (language.length() > 0 ? new Locale(language, country,
0625: variant) : null);
0626: }
0627:
0628: //---------------------------------------------------------------------
0629: // Convenience methods for working with String arrays
0630: //---------------------------------------------------------------------
0631:
0632: /**
0633: * Append the given String to the given String array, returning a new array
0634: * consisting of the input array contents plus the given String.
0635: * @param array the array to append to (can be <code>null</code>)
0636: * @param str the String to append
0637: * @return the new array (never <code>null</code>)
0638: */
0639: public static String[] addStringToArray(String[] array, String str) {
0640: if (ObjectUtils.isEmpty(array)) {
0641: return new String[] { str };
0642: }
0643: String[] newArr = new String[array.length + 1];
0644: System.arraycopy(array, 0, newArr, 0, array.length);
0645: newArr[array.length] = str;
0646: return newArr;
0647: }
0648:
0649: /**
0650: * Concatenate the given String arrays into one,
0651: * with overlapping array elements included twice.
0652: * <p>The order of elements in the original arrays is preserved.
0653: * @param array1 the first array (can be <code>null</code>)
0654: * @param array2 the second array (can be <code>null</code>)
0655: * @return the new array (<code>null</code> if both given arrays were <code>null</code>)
0656: */
0657: public static String[] concatenateStringArrays(String[] array1,
0658: String[] array2) {
0659: if (ObjectUtils.isEmpty(array1)) {
0660: return array2;
0661: }
0662: if (ObjectUtils.isEmpty(array2)) {
0663: return array1;
0664: }
0665: String[] newArr = new String[array1.length + array2.length];
0666: System.arraycopy(array1, 0, newArr, 0, array1.length);
0667: System.arraycopy(array2, 0, newArr, array1.length,
0668: array2.length);
0669: return newArr;
0670: }
0671:
0672: /**
0673: * Merge the given String arrays into one, with overlapping
0674: * array elements only included once.
0675: * <p>The order of elements in the original arrays is preserved
0676: * (with the exception of overlapping elements, which are only
0677: * included on their first occurence).
0678: * @param array1 the first array (can be <code>null</code>)
0679: * @param array2 the second array (can be <code>null</code>)
0680: * @return the new array (<code>null</code> if both given arrays were <code>null</code>)
0681: */
0682: public static String[] mergeStringArrays(String[] array1,
0683: String[] array2) {
0684: if (ObjectUtils.isEmpty(array1)) {
0685: return array2;
0686: }
0687: if (ObjectUtils.isEmpty(array2)) {
0688: return array1;
0689: }
0690: List result = new ArrayList();
0691: result.addAll(Arrays.asList(array1));
0692: for (int i = 0; i < array2.length; i++) {
0693: String str = array2[i];
0694: if (!result.contains(str)) {
0695: result.add(str);
0696: }
0697: }
0698: return toStringArray(result);
0699: }
0700:
0701: /**
0702: * Turn given source String array into sorted array.
0703: * @param array the source array
0704: * @return the sorted array (never <code>null</code>)
0705: */
0706: public static String[] sortStringArray(String[] array) {
0707: if (ObjectUtils.isEmpty(array)) {
0708: return new String[0];
0709: }
0710: Arrays.sort(array);
0711: return array;
0712: }
0713:
0714: /**
0715: * Copy the given Collection into a String array.
0716: * The Collection must contain String elements only.
0717: * @param collection the Collection to copy
0718: * @return the String array (<code>null</code> if the passed-in
0719: * Collection was <code>null</code>)
0720: */
0721: public static String[] toStringArray(Collection collection) {
0722: if (collection == null) {
0723: return null;
0724: }
0725: return (String[]) collection.toArray(new String[collection
0726: .size()]);
0727: }
0728:
0729: /**
0730: * Copy the given Enumeration into a String array.
0731: * The Enumeration must contain String elements only.
0732: * @param enumeration the Enumeration to copy
0733: * @return the String array (<code>null</code> if the passed-in
0734: * Enumeration was <code>null</code>)
0735: */
0736: public static String[] toStringArray(Enumeration enumeration) {
0737: if (enumeration == null) {
0738: return null;
0739: }
0740: List list = Collections.list(enumeration);
0741: return (String[]) list.toArray(new String[list.size()]);
0742: }
0743:
0744: /**
0745: * Trim the elements of the given String array,
0746: * calling <code>String.trim()</code> on each of them.
0747: * @param array the original String array
0748: * @return the resulting array (of the same size) with trimmed elements
0749: */
0750: public static String[] trimArrayElements(String[] array) {
0751: if (ObjectUtils.isEmpty(array)) {
0752: return new String[0];
0753: }
0754: String[] result = new String[array.length];
0755: for (int i = 0; i < array.length; i++) {
0756: String element = array[i];
0757: result[i] = (element != null ? element.trim() : null);
0758: }
0759: return result;
0760: }
0761:
0762: /**
0763: * Remove duplicate Strings from the given array.
0764: * Also sorts the array, as it uses a TreeSet.
0765: * @param array the String array
0766: * @return an array without duplicates, in natural sort order
0767: */
0768: public static String[] removeDuplicateStrings(String[] array) {
0769: if (ObjectUtils.isEmpty(array)) {
0770: return array;
0771: }
0772: Set set = new TreeSet();
0773: for (int i = 0; i < array.length; i++) {
0774: set.add(array[i]);
0775: }
0776: return toStringArray(set);
0777: }
0778:
0779: /**
0780: * Split a String at the first occurrence of the delimiter.
0781: * Does not include the delimiter in the result.
0782: * @param toSplit the string to split
0783: * @param delimiter to split the string up with
0784: * @return a two element array with index 0 being before the delimiter, and
0785: * index 1 being after the delimiter (neither element includes the delimiter);
0786: * or <code>null</code> if the delimiter wasn't found in the given input String
0787: */
0788: public static String[] split(String toSplit, String delimiter) {
0789: if (!hasLength(toSplit) || !hasLength(delimiter)) {
0790: return null;
0791: }
0792: int offset = toSplit.indexOf(delimiter);
0793: if (offset < 0) {
0794: return null;
0795: }
0796: String beforeDelimiter = toSplit.substring(0, offset);
0797: String afterDelimiter = toSplit.substring(offset
0798: + delimiter.length());
0799: return new String[] { beforeDelimiter, afterDelimiter };
0800: }
0801:
0802: /**
0803: * Take an array Strings and split each element based on the given delimiter.
0804: * A <code>Properties</code> instance is then generated, with the left of the
0805: * delimiter providing the key, and the right of the delimiter providing the value.
0806: * <p>Will trim both the key and value before adding them to the
0807: * <code>Properties</code> instance.
0808: * @param array the array to process
0809: * @param delimiter to split each element using (typically the equals symbol)
0810: * @return a <code>Properties</code> instance representing the array contents,
0811: * or <code>null</code> if the array to process was null or empty
0812: */
0813: public static Properties splitArrayElementsIntoProperties(
0814: String[] array, String delimiter) {
0815: return splitArrayElementsIntoProperties(array, delimiter, null);
0816: }
0817:
0818: /**
0819: * Take an array Strings and split each element based on the given delimiter.
0820: * A <code>Properties</code> instance is then generated, with the left of the
0821: * delimiter providing the key, and the right of the delimiter providing the value.
0822: * <p>Will trim both the key and value before adding them to the
0823: * <code>Properties</code> instance.
0824: * @param array the array to process
0825: * @param delimiter to split each element using (typically the equals symbol)
0826: * @param charsToDelete one or more characters to remove from each element
0827: * prior to attempting the split operation (typically the quotation mark
0828: * symbol), or <code>null</code> if no removal should occur
0829: * @return a <code>Properties</code> instance representing the array contents,
0830: * or <code>null</code> if the array to process was <code>null</code> or empty
0831: */
0832: public static Properties splitArrayElementsIntoProperties(
0833: String[] array, String delimiter, String charsToDelete) {
0834:
0835: if (ObjectUtils.isEmpty(array)) {
0836: return null;
0837: }
0838: Properties result = new Properties();
0839: for (int i = 0; i < array.length; i++) {
0840: String element = array[i];
0841: if (charsToDelete != null) {
0842: element = deleteAny(array[i], charsToDelete);
0843: }
0844: String[] splittedElement = split(element, delimiter);
0845: if (splittedElement == null) {
0846: continue;
0847: }
0848: result.setProperty(splittedElement[0].trim(),
0849: splittedElement[1].trim());
0850: }
0851: return result;
0852: }
0853:
0854: /**
0855: * Tokenize the given String into a String array via a StringTokenizer.
0856: * Trims tokens and omits empty tokens.
0857: * <p>The given delimiters string is supposed to consist of any number of
0858: * delimiter characters. Each of those characters can be used to separate
0859: * tokens. A delimiter is always a single character; for multi-character
0860: * delimiters, consider using <code>delimitedListToStringArray</code>
0861: * @param str the String to tokenize
0862: * @param delimiters the delimiter characters, assembled as String
0863: * (each of those characters is individually considered as delimiter).
0864: * @return an array of the tokens
0865: * @see java.util.StringTokenizer
0866: * @see java.lang.String#trim()
0867: * @see #delimitedListToStringArray
0868: */
0869: public static String[] tokenizeToStringArray(String str,
0870: String delimiters) {
0871: return tokenizeToStringArray(str, delimiters, true, true);
0872: }
0873:
0874: /**
0875: * Tokenize the given String into a String array via a StringTokenizer.
0876: * <p>The given delimiters string is supposed to consist of any number of
0877: * delimiter characters. Each of those characters can be used to separate
0878: * tokens. A delimiter is always a single character; for multi-character
0879: * delimiters, consider using <code>delimitedListToStringArray</code>
0880: * @param str the String to tokenize
0881: * @param delimiters the delimiter characters, assembled as String
0882: * (each of those characters is individually considered as delimiter)
0883: * @param trimTokens trim the tokens via String's <code>trim</code>
0884: * @param ignoreEmptyTokens omit empty tokens from the result array
0885: * (only applies to tokens that are empty after trimming; StringTokenizer
0886: * will not consider subsequent delimiters as token in the first place).
0887: * @return an array of the tokens (<code>null</code> if the input String
0888: * was <code>null</code>)
0889: * @see java.util.StringTokenizer
0890: * @see java.lang.String#trim()
0891: * @see #delimitedListToStringArray
0892: */
0893: public static String[] tokenizeToStringArray(String str,
0894: String delimiters, boolean trimTokens,
0895: boolean ignoreEmptyTokens) {
0896:
0897: if (str == null) {
0898: return null;
0899: }
0900: StringTokenizer st = new StringTokenizer(str, delimiters);
0901: List tokens = new ArrayList();
0902: while (st.hasMoreTokens()) {
0903: String token = st.nextToken();
0904: if (trimTokens) {
0905: token = token.trim();
0906: }
0907: if (!ignoreEmptyTokens || token.length() > 0) {
0908: tokens.add(token);
0909: }
0910: }
0911: return toStringArray(tokens);
0912: }
0913:
0914: /**
0915: * Take a String which is a delimited list and convert it to a String array.
0916: * <p>A single delimiter can consists of more than one character: It will still
0917: * be considered as single delimiter string, rather than as bunch of potential
0918: * delimiter characters - in contrast to <code>tokenizeToStringArray</code>.
0919: * @param str the input String
0920: * @param delimiter the delimiter between elements (this is a single delimiter,
0921: * rather than a bunch individual delimiter characters)
0922: * @return an array of the tokens in the list
0923: * @see #tokenizeToStringArray
0924: */
0925: public static String[] delimitedListToStringArray(String str,
0926: String delimiter) {
0927: return delimitedListToStringArray(str, delimiter, null);
0928: }
0929:
0930: /**
0931: * Take a String which is a delimited list and convert it to a String array.
0932: * <p>A single delimiter can consists of more than one character: It will still
0933: * be considered as single delimiter string, rather than as bunch of potential
0934: * delimiter characters - in contrast to <code>tokenizeToStringArray</code>.
0935: * @param str the input String
0936: * @param delimiter the delimiter between elements (this is a single delimiter,
0937: * rather than a bunch individual delimiter characters)
0938: * @param charsToDelete a set of characters to delete. Useful for deleting unwanted
0939: * line breaks: e.g. "\r\n\f" will delete all new lines and line feeds in a String.
0940: * @return an array of the tokens in the list
0941: * @see #tokenizeToStringArray
0942: */
0943: public static String[] delimitedListToStringArray(String str,
0944: String delimiter, String charsToDelete) {
0945: if (str == null) {
0946: return new String[0];
0947: }
0948: if (delimiter == null) {
0949: return new String[] { str };
0950: }
0951: List result = new ArrayList();
0952: if ("".equals(delimiter)) {
0953: for (int i = 0; i < str.length(); i++) {
0954: result.add(deleteAny(str.substring(i, i + 1),
0955: charsToDelete));
0956: }
0957: } else {
0958: int pos = 0;
0959: int delPos = 0;
0960: while ((delPos = str.indexOf(delimiter, pos)) != -1) {
0961: result.add(deleteAny(str.substring(pos, delPos),
0962: charsToDelete));
0963: pos = delPos + delimiter.length();
0964: }
0965: if (str.length() > 0 && pos <= str.length()) {
0966: // Add rest of String, but not in case of empty input.
0967: result
0968: .add(deleteAny(str.substring(pos),
0969: charsToDelete));
0970: }
0971: }
0972: return toStringArray(result);
0973: }
0974:
0975: /**
0976: * Convert a CSV list into an array of Strings.
0977: * @param str the input String
0978: * @return an array of Strings, or the empty array in case of empty input
0979: */
0980: public static String[] commaDelimitedListToStringArray(String str) {
0981: return delimitedListToStringArray(str, ",");
0982: }
0983:
0984: /**
0985: * Convenience method to convert a CSV string list to a set.
0986: * Note that this will suppress duplicates.
0987: * @param str the input String
0988: * @return a Set of String entries in the list
0989: */
0990: public static Set commaDelimitedListToSet(String str) {
0991: Set set = new TreeSet();
0992: String[] tokens = commaDelimitedListToStringArray(str);
0993: for (int i = 0; i < tokens.length; i++) {
0994: set.add(tokens[i]);
0995: }
0996: return set;
0997: }
0998:
0999: /**
1000: * Convenience method to return a Collection as a delimited (e.g. CSV)
1001: * String. E.g. useful for <code>toString()</code> implementations.
1002: * @param coll the Collection to display
1003: * @param delim the delimiter to use (probably a ",")
1004: * @param prefix the String to start each element with
1005: * @param suffix the String to end each element with
1006: * @return the delimited String
1007: */
1008: public static String collectionToDelimitedString(Collection coll,
1009: String delim, String prefix, String suffix) {
1010: if (CollectionUtils.isEmpty(coll)) {
1011: return "";
1012: }
1013: StringBuffer sb = new StringBuffer();
1014: Iterator it = coll.iterator();
1015: while (it.hasNext()) {
1016: sb.append(prefix).append(it.next()).append(suffix);
1017: if (it.hasNext()) {
1018: sb.append(delim);
1019: }
1020: }
1021: return sb.toString();
1022: }
1023:
1024: /**
1025: * Convenience method to return a Collection as a delimited (e.g. CSV)
1026: * String. E.g. useful for <code>toString()</code> implementations.
1027: * @param coll the Collection to display
1028: * @param delim the delimiter to use (probably a ",")
1029: * @return the delimited String
1030: */
1031: public static String collectionToDelimitedString(Collection coll,
1032: String delim) {
1033: return collectionToDelimitedString(coll, delim, "", "");
1034: }
1035:
1036: /**
1037: * Convenience method to return a Collection as a CSV String.
1038: * E.g. useful for <code>toString()</code> implementations.
1039: * @param coll the Collection to display
1040: * @return the delimited String
1041: */
1042: public static String collectionToCommaDelimitedString(
1043: Collection coll) {
1044: return collectionToDelimitedString(coll, ",");
1045: }
1046:
1047: /**
1048: * Convenience method to return a String array as a delimited (e.g. CSV)
1049: * String. E.g. useful for <code>toString()</code> implementations.
1050: * @param arr the array to display
1051: * @param delim the delimiter to use (probably a ",")
1052: * @return the delimited String
1053: */
1054: public static String arrayToDelimitedString(Object[] arr,
1055: String delim) {
1056: if (ObjectUtils.isEmpty(arr)) {
1057: return "";
1058: }
1059: StringBuffer sb = new StringBuffer();
1060: for (int i = 0; i < arr.length; i++) {
1061: if (i > 0) {
1062: sb.append(delim);
1063: }
1064: sb.append(arr[i]);
1065: }
1066: return sb.toString();
1067: }
1068:
1069: /**
1070: * Convenience method to return a String array as a CSV String.
1071: * E.g. useful for <code>toString()</code> implementations.
1072: * @param arr the array to display
1073: * @return the delimited String
1074: */
1075: public static String arrayToCommaDelimitedString(Object[] arr) {
1076: return arrayToDelimitedString(arr, ",");
1077: }
1078:
1079: }
|