001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.util;
018:
019: import java.util.ArrayList;
020: import java.util.Arrays;
021: import java.util.Collection;
022: import java.util.Iterator;
023: import java.util.LinkedList;
024: import java.util.List;
025: import java.util.Locale;
026: import java.util.Properties;
027: import java.util.Set;
028: import java.util.StringTokenizer;
029: import java.util.TreeSet;
030:
031: /**
032: * Miscellaneous string utility methods. Mainly for internal use
033: * within the framework; consider Jakarta's Commons Lang for a more
034: * comprehensive suite of string utilities.
035: *
036: * <p>This class delivers some simple functionality that should really
037: * be provided by the core Java String and StringBuffer classes, such
038: * as the ability to replace all occurrences of a given substring in a
039: * target string. It also provides easy-to-use methods to convert between
040: * delimited strings, such as CSV strings, and collections and arrays.
041: *
042: * @author Rod Johnson
043: * @author Juergen Hoeller
044: * @author Keith Donald
045: * @author Rob Harrop
046: * @since 16 April 2001
047: * @see org.apache.commons.lang.StringUtils
048: */
049: public abstract class StringUtils {
050:
051: private static final String FOLDER_SEPARATOR = "/";
052:
053: private static final String WINDOWS_FOLDER_SEPARATOR = "\\";
054:
055: private static final String TOP_PATH = "..";
056:
057: private static final String CURRENT_PATH = ".";
058:
059: private static final char EXTENSION_SEPARATOR = '.';
060:
061: //---------------------------------------------------------------------
062: // General convenience methods for working with Strings
063: //---------------------------------------------------------------------
064:
065: /**
066: * Check that the given String is neither <code>null</code> nor of length 0.
067: * Note: Will return <code>true</code> for a String that purely consists of whitespace.
068: * <p><pre>
069: * StringUtils.hasLength(null) = false
070: * StringUtils.hasLength("") = false
071: * StringUtils.hasLength(" ") = true
072: * StringUtils.hasLength("Hello") = true
073: * </pre>
074: * @param str the String to check (may be <code>null</code>)
075: * @return <code>true</code> if the String is not null and has length
076: * @see #hasText(String)
077: */
078: public static boolean hasLength(String str) {
079: return (str != null && str.length() > 0);
080: }
081:
082: /**
083: * Check whether the given String has actual text.
084: * More specifically, returns <code>true</code> if the string not <code>null<code>,
085: * its length is greater than 0, and it contains at least one non-whitespace character.
086: * <p><pre>
087: * StringUtils.hasText(null) = false
088: * StringUtils.hasText("") = false
089: * StringUtils.hasText(" ") = false
090: * StringUtils.hasText("12345") = true
091: * StringUtils.hasText(" 12345 ") = true
092: * </pre>
093: * @param str the String to check (may be <code>null</code>)
094: * @return <code>true</code> if the String is not <code>null</code>, its length is
095: * greater than 0, and is does not contain whitespace only
096: * @see java.lang.Character#isWhitespace
097: */
098: public static boolean hasText(String str) {
099: if (!hasLength(str)) {
100: return false;
101: }
102: int strLen = str.length();
103: for (int i = 0; i < strLen; i++) {
104: if (!Character.isWhitespace(str.charAt(i))) {
105: return true;
106: }
107: }
108: return false;
109: }
110:
111: /**
112: * Check whether the given String contains any whitespace characters.
113: * @param str the String to check (may be <code>null</code>)
114: * @return <code>true</code> if the String is not empty and
115: * contains at least 1 whitespace character
116: * @see java.lang.Character#isWhitespace
117: */
118: public static boolean containsWhitespace(String str) {
119: if (!hasLength(str)) {
120: return false;
121: }
122: int strLen = str.length();
123: for (int i = 0; i < strLen; i++) {
124: if (Character.isWhitespace(str.charAt(i))) {
125: return true;
126: }
127: }
128: return false;
129: }
130:
131: /**
132: * Trim leading and trailing whitespace from the given String.
133: * @param str the String to check
134: * @return the trimmed String
135: * @see java.lang.Character#isWhitespace
136: */
137: public static String trimWhitespace(String str) {
138: if (!hasLength(str)) {
139: return str;
140: }
141: StringBuffer buf = new StringBuffer(str);
142: while (buf.length() > 0
143: && Character.isWhitespace(buf.charAt(0))) {
144: buf.deleteCharAt(0);
145: }
146: while (buf.length() > 0
147: && Character.isWhitespace(buf.charAt(buf.length() - 1))) {
148: buf.deleteCharAt(buf.length() - 1);
149: }
150: return buf.toString();
151: }
152:
153: /**
154: * Trim leading whitespace from the given String.
155: * @param str the String to check
156: * @return the trimmed String
157: * @see java.lang.Character#isWhitespace
158: */
159: public static String trimLeadingWhitespace(String str) {
160: if (!hasLength(str)) {
161: return str;
162: }
163: StringBuffer buf = new StringBuffer(str);
164: while (buf.length() > 0
165: && Character.isWhitespace(buf.charAt(0))) {
166: buf.deleteCharAt(0);
167: }
168: return buf.toString();
169: }
170:
171: /**
172: * Trim trailing whitespace from the given String.
173: * @param str the String to check
174: * @return the trimmed String
175: * @see java.lang.Character#isWhitespace
176: */
177: public static String trimTrailingWhitespace(String str) {
178: if (!hasLength(str)) {
179: return str;
180: }
181: StringBuffer buf = new StringBuffer(str);
182: while (buf.length() > 0
183: && Character.isWhitespace(buf.charAt(buf.length() - 1))) {
184: buf.deleteCharAt(buf.length() - 1);
185: }
186: return buf.toString();
187: }
188:
189: /**
190: * Trim <i>all</i> whitespace from the given String:
191: * leading, trailing, and inbetween characters.
192: * @param str the String to check
193: * @return the trimmed String
194: * @see java.lang.Character#isWhitespace
195: */
196: public static String trimAllWhitespace(String str) {
197: if (!hasLength(str)) {
198: return str;
199: }
200: StringBuffer buf = new StringBuffer(str);
201: int index = 0;
202: while (buf.length() > index) {
203: if (Character.isWhitespace(buf.charAt(index))) {
204: buf.deleteCharAt(index);
205: } else {
206: index++;
207: }
208: }
209: return buf.toString();
210: }
211:
212: /**
213: * Test if the given String starts with the specified prefix,
214: * ignoring upper/lower case.
215: * @param str the String to check
216: * @param prefix the prefix to look for
217: * @see java.lang.String#startsWith
218: */
219: public static boolean startsWithIgnoreCase(String str, String prefix) {
220: if (str == null || prefix == null) {
221: return false;
222: }
223: if (str.startsWith(prefix)) {
224: return true;
225: }
226: if (str.length() < prefix.length()) {
227: return false;
228: }
229: String lcStr = str.substring(0, prefix.length()).toLowerCase();
230: String lcPrefix = prefix.toLowerCase();
231: return lcStr.equals(lcPrefix);
232: }
233:
234: /**
235: * Test if the given String ends with the specified suffix,
236: * ignoring upper/lower case.
237: * @param str the String to check
238: * @param suffix the suffix to look for
239: * @see java.lang.String#endsWith
240: */
241: public static boolean endsWithIgnoreCase(String str, String suffix) {
242: if (str == null || suffix == null) {
243: return false;
244: }
245: if (str.endsWith(suffix)) {
246: return true;
247: }
248: if (str.length() < suffix.length()) {
249: return false;
250: }
251:
252: String lcStr = str.substring(str.length() - suffix.length())
253: .toLowerCase();
254: String lcSuffix = suffix.toLowerCase();
255: return lcStr.equals(lcSuffix);
256: }
257:
258: /**
259: * Count the occurrences of the substring in string s.
260: * @param str string to search in. Return 0 if this is null.
261: * @param sub string to search for. Return 0 if this is null.
262: */
263: public static int countOccurrencesOf(String str, String sub) {
264: if (str == null || sub == null || str.length() == 0
265: || sub.length() == 0) {
266: return 0;
267: }
268: int count = 0, pos = 0, idx = 0;
269: while ((idx = str.indexOf(sub, pos)) != -1) {
270: ++count;
271: pos = idx + sub.length();
272: }
273: return count;
274: }
275:
276: /**
277: * Replace all occurences of a substring within a string with
278: * another string.
279: * @param inString String to examine
280: * @param oldPattern String to replace
281: * @param newPattern String to insert
282: * @return a String with the replacements
283: */
284: public static String replace(String inString, String oldPattern,
285: String newPattern) {
286: if (inString == null) {
287: return null;
288: }
289: if (oldPattern == null || newPattern == null) {
290: return inString;
291: }
292:
293: StringBuffer sbuf = new StringBuffer();
294: // output StringBuffer we'll build up
295: int pos = 0; // our position in the old string
296: int index = inString.indexOf(oldPattern);
297: // the index of an occurrence we've found, or -1
298: int patLen = oldPattern.length();
299: while (index >= 0) {
300: sbuf.append(inString.substring(pos, index));
301: sbuf.append(newPattern);
302: pos = index + patLen;
303: index = inString.indexOf(oldPattern, pos);
304: }
305: sbuf.append(inString.substring(pos));
306:
307: // remember to append any characters to the right of a match
308: return sbuf.toString();
309: }
310:
311: /**
312: * Delete all occurrences of the given substring.
313: * @param pattern the pattern to delete all occurrences of
314: */
315: public static String delete(String inString, String pattern) {
316: return replace(inString, pattern, "");
317: }
318:
319: /**
320: * Delete any character in a given string.
321: * @param charsToDelete a set of characters to delete.
322: * E.g. "az\n" will delete 'a's, 'z's and new lines.
323: */
324: public static String deleteAny(String inString, String charsToDelete) {
325: if (inString == null || charsToDelete == null) {
326: return inString;
327: }
328: StringBuffer out = new StringBuffer();
329: for (int i = 0; i < inString.length(); i++) {
330: char c = inString.charAt(i);
331: if (charsToDelete.indexOf(c) == -1) {
332: out.append(c);
333: }
334: }
335: return out.toString();
336: }
337:
338: //---------------------------------------------------------------------
339: // Convenience methods for working with formatted Strings
340: //---------------------------------------------------------------------
341:
342: /**
343: * Quote the given String with single quotes.
344: * @param str the input String (e.g. "myString")
345: * @return the quoted String (e.g. "'myString'"),
346: * or <code>null<code> if the input was <code>null</code>
347: */
348: public static String quote(String str) {
349: return (str != null ? "'" + str + "'" : null);
350: }
351:
352: /**
353: * Turn the given Object into a String with single quotes
354: * if it is a String; keeping the Object as-is else.
355: * @param obj the input Object (e.g. "myString")
356: * @return the quoted String (e.g. "'myString'"),
357: * or the input object as-is if not a String
358: */
359: public static Object quoteIfString(Object obj) {
360: return (obj instanceof String ? quote((String) obj) : obj);
361: }
362:
363: /**
364: * Unqualify a string qualified by a '.' dot character. For example,
365: * "this.name.is.qualified", returns "qualified".
366: * @param qualifiedName the qualified name
367: */
368: public static String unqualify(String qualifiedName) {
369: return unqualify(qualifiedName, '.');
370: }
371:
372: /**
373: * Unqualify a string qualified by a separator character. For example,
374: * "this:name:is:qualified" returns "qualified" if using a ':' separator.
375: * @param qualifiedName the qualified name
376: * @param separator the separator
377: */
378: public static String unqualify(String qualifiedName, char separator) {
379: return qualifiedName.substring(qualifiedName
380: .lastIndexOf(separator) + 1);
381: }
382:
383: /**
384: * Capitalize a <code>String</code>, changing the first letter to
385: * upper case as per {@link Character#toUpperCase(char)}.
386: * No other letters are changed.
387: * @param str the String to capitalize, may be <code>null</code>
388: * @return the capitalized String, <code>null</code> if null
389: */
390: public static String capitalize(String str) {
391: return changeFirstCharacterCase(str, true);
392: }
393:
394: /**
395: * Uncapitalize a <code>String</code>, changing the first letter to
396: * lower case as per {@link Character#toLowerCase(char)}.
397: * No other letters are changed.
398: * @param str the String to uncapitalize, may be <code>null</code>
399: * @return the uncapitalized String, <code>null</code> if null
400: */
401: public static String uncapitalize(String str) {
402: return changeFirstCharacterCase(str, false);
403: }
404:
405: private static String changeFirstCharacterCase(String str,
406: boolean capitalize) {
407: if (str == null || str.length() == 0) {
408: return str;
409: }
410: StringBuffer buf = new StringBuffer(str.length());
411: if (capitalize) {
412: buf.append(Character.toUpperCase(str.charAt(0)));
413: } else {
414: buf.append(Character.toLowerCase(str.charAt(0)));
415: }
416: buf.append(str.substring(1));
417: return buf.toString();
418: }
419:
420: /**
421: * Extract the filename from the given path,
422: * e.g. "mypath/myfile.txt" -> "myfile.txt".
423: * @param path the file path (may be <code>null</code>)
424: * @return the extracted filename, or <code>null</code> if none
425: */
426: public static String getFilename(String path) {
427: if (path == null) {
428: return null;
429: }
430: int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR);
431: return (separatorIndex != -1 ? path
432: .substring(separatorIndex + 1) : path);
433: }
434:
435: /**
436: * Extract the filename extension from the given path,
437: * e.g. "mypath/myfile.txt" -> "txt".
438: * @param path the file path (may be <code>null</code>)
439: * @return the extracted filename extension, or <code>null</code> if none
440: */
441: public static String getFilenameExtension(String path) {
442: if (path == null) {
443: return null;
444: }
445: int sepIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
446: return (sepIndex != -1 ? path.substring(sepIndex + 1) : null);
447: }
448:
449: /**
450: * Strip the filename extension from the given path,
451: * e.g. "mypath/myfile.txt" -> "mypath/myfile".
452: * @param path the file path (may be <code>null</code>)
453: * @return the path with stripped filename extension,
454: * or <code>null</code> if none
455: */
456: public static String stripFilenameExtension(String path) {
457: if (path == null) {
458: return null;
459: }
460: int sepIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
461: return (sepIndex != -1 ? path.substring(0, sepIndex) : path);
462: }
463:
464: /**
465: * Apply the given relative path to the given path,
466: * assuming standard Java folder separation (i.e. "/" separators);
467: * @param path the path to start from (usually a full file path)
468: * @param relativePath the relative path to apply
469: * (relative to the full file path above)
470: * @return the full file path that results from applying the relative path
471: */
472: public static String applyRelativePath(String path,
473: String relativePath) {
474: int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR);
475: if (separatorIndex != -1) {
476: String newPath = path.substring(0, separatorIndex);
477: if (!relativePath.startsWith(FOLDER_SEPARATOR)) {
478: newPath += FOLDER_SEPARATOR;
479: }
480: return newPath + relativePath;
481: } else {
482: return relativePath;
483: }
484: }
485:
486: /**
487: * Normalize the path by suppressing sequences like "path/.." and
488: * inner simple dots.
489: * <p>The result is convenient for path comparison. For other uses,
490: * notice that Windows separators ("\") are replaced by simple slashes.
491: * @param path the original path
492: * @return the normalized path
493: */
494: public static String cleanPath(String path) {
495: String pathToUse = replace(path, WINDOWS_FOLDER_SEPARATOR,
496: FOLDER_SEPARATOR);
497:
498: // Strip prefix from path to analyze, to not treat it as part of the
499: // first path element. This is necessary to correctly parse paths like
500: // "file:core/../core/io/Resource.class", where the ".." should just
501: // strip the first "core" directory while keeping the "file:" prefix.
502: int prefixIndex = pathToUse.indexOf(":");
503: String prefix = "";
504: if (prefixIndex != -1) {
505: prefix = pathToUse.substring(0, prefixIndex + 1);
506: pathToUse = pathToUse.substring(prefixIndex + 1);
507: }
508:
509: String[] pathArray = delimitedListToStringArray(pathToUse,
510: FOLDER_SEPARATOR);
511: List pathElements = new LinkedList();
512: int tops = 0;
513:
514: for (int i = pathArray.length - 1; i >= 0; i--) {
515: if (CURRENT_PATH.equals(pathArray[i])) {
516: // Points to current directory - drop it.
517: } else if (TOP_PATH.equals(pathArray[i])) {
518: // Registering top path found.
519: tops++;
520: } else {
521: if (tops > 0) {
522: // Merging path element with corresponding to top path.
523: tops--;
524: } else {
525: // Normal path element found.
526: pathElements.add(0, pathArray[i]);
527: }
528: }
529: }
530:
531: // Remaining top paths need to be retained.
532: for (int i = 0; i < tops; i++) {
533: pathElements.add(0, TOP_PATH);
534: }
535:
536: return prefix
537: + collectionToDelimitedString(pathElements,
538: FOLDER_SEPARATOR);
539: }
540:
541: /**
542: * Compare two paths after normalization of them.
543: * @param path1 First path for comparizon
544: * @param path2 Second path for comparizon
545: * @return whether the two paths are equivalent after normalization
546: */
547: public static boolean pathEquals(String path1, String path2) {
548: return cleanPath(path1).equals(cleanPath(path2));
549: }
550:
551: /**
552: * Parse the given locale string into a <code>java.util.Locale</code>.
553: * This is the inverse operation of Locale's <code>toString</code>.
554: * @param localeString the locale string, following
555: * <code>java.util.Locale</code>'s toString format ("en", "en_UK", etc).
556: * Also accepts spaces as separators, as alternative to underscores.
557: * @return a corresponding Locale instance
558: */
559: public static Locale parseLocaleString(String localeString) {
560: String[] parts = tokenizeToStringArray(localeString, "_ ",
561: false, false);
562: String language = (parts.length > 0 ? parts[0] : "");
563: String country = (parts.length > 1 ? parts[1] : "");
564: String variant = (parts.length > 2 ? parts[2] : "");
565: return (language.length() > 0 ? new Locale(language, country,
566: variant) : null);
567: }
568:
569: //---------------------------------------------------------------------
570: // Convenience methods for working with String arrays
571: //---------------------------------------------------------------------
572:
573: /**
574: * Append the given String to the given String array, returning a new array
575: * consisting of the input array contents plus the given String.
576: * @param array the array to append to (can be <code>null</code>)
577: * @param str the String to append
578: * @return the new array (never <code>null</code>)
579: */
580: public static String[] addStringToArray(String[] array, String str) {
581: if (ObjectUtils.isEmpty(array)) {
582: return new String[] { str };
583: }
584: String[] newArr = new String[array.length + 1];
585: System.arraycopy(array, 0, newArr, 0, array.length);
586: newArr[array.length] = str;
587: return newArr;
588: }
589:
590: /**
591: * Concatenate the given String arrays into one,
592: * with overlapping array elements included twice.
593: * <p>The order of elements in the original arrays is preserved.
594: * @param array1 the first array (can be <code>null</code>)
595: * @param array2 the second array (can be <code>null</code>)
596: * @return the new array (<code>null</code> if both given arrays were <code>null</code>)
597: */
598: public static String[] concatenateStringArrays(String[] array1,
599: String[] array2) {
600: if (ObjectUtils.isEmpty(array1)) {
601: return array2;
602: }
603: if (ObjectUtils.isEmpty(array2)) {
604: return array1;
605: }
606: String[] newArr = new String[array1.length + array2.length];
607: System.arraycopy(array1, 0, newArr, 0, array1.length);
608: System.arraycopy(array2, 0, newArr, array1.length,
609: array2.length);
610: return newArr;
611: }
612:
613: /**
614: * Merge the given String arrays into one, with overlapping
615: * array elements only included once.
616: * <p>The order of elements in the original arrays is preserved
617: * (with the exception of overlapping elements, which are only
618: * included on their first occurence).
619: * @param array1 the first array (can be <code>null</code>)
620: * @param array2 the second array (can be <code>null</code>)
621: * @return the new array (<code>null</code> if both given arrays were <code>null</code>)
622: */
623: public static String[] mergeStringArrays(String[] array1,
624: String[] array2) {
625: if (ObjectUtils.isEmpty(array1)) {
626: return array2;
627: }
628: if (ObjectUtils.isEmpty(array2)) {
629: return array1;
630: }
631: List result = new ArrayList();
632: result.addAll(Arrays.asList(array1));
633: for (int i = 0; i < array2.length; i++) {
634: String str = array2[i];
635: if (!result.contains(str)) {
636: result.add(str);
637: }
638: }
639: return toStringArray(result);
640: }
641:
642: /**
643: * Turn given source String array into sorted array.
644: * @param array the source array
645: * @return the sorted array (never <code>null</code>)
646: */
647: public static String[] sortStringArray(String[] array) {
648: if (ObjectUtils.isEmpty(array)) {
649: return new String[0];
650: }
651: Arrays.sort(array);
652: return array;
653: }
654:
655: /**
656: * Copy the given Collection into a String array.
657: * The Collection must contain String elements only.
658: * @param collection the Collection to copy
659: * @return the String array (<code>null</code> if the passed-in
660: * Collection was <code>null</code>)
661: */
662: public static String[] toStringArray(Collection collection) {
663: if (collection == null) {
664: return null;
665: }
666: return (String[]) collection.toArray(new String[collection
667: .size()]);
668: }
669:
670: /**
671: * Remove duplicate Strings from the given array.
672: * Also sorts the array, as it uses a TreeSet.
673: * @param array the String array
674: * @return an array without duplicates, in natural sort order
675: */
676: public static String[] removeDuplicateStrings(String[] array) {
677: if (ObjectUtils.isEmpty(array)) {
678: return array;
679: }
680: Set set = new TreeSet();
681: for (int i = 0; i < array.length; i++) {
682: set.add(array[i]);
683: }
684: return toStringArray(set);
685: }
686:
687: /**
688: * Split a String at the first occurrence of the delimiter.
689: * Does not include the delimiter in the result.
690: * @param toSplit the string to split
691: * @param delimiter to split the string up with
692: * @return a two element array with index 0 being before the delimiter, and
693: * index 1 being after the delimiter (neither element includes the delimiter);
694: * or <code>null</code> if the delimiter wasn't found in the given input String
695: */
696: public static String[] split(String toSplit, String delimiter) {
697: if (!hasLength(toSplit) || !hasLength(delimiter)) {
698: return null;
699: }
700: int offset = toSplit.indexOf(delimiter);
701: if (offset < 0) {
702: return null;
703: }
704: String beforeDelimiter = toSplit.substring(0, offset);
705: String afterDelimiter = toSplit.substring(offset
706: + delimiter.length());
707: return new String[] { beforeDelimiter, afterDelimiter };
708: }
709:
710: /**
711: * Take an array Strings and split each element based on the given delimiter.
712: * A <code>Properties</code> instance is then generated, with the left of the
713: * delimiter providing the key, and the right of the delimiter providing the value.
714: * <p>Will trim both the key and value before adding them to the
715: * <code>Properties</code> instance.
716: * @param array the array to process
717: * @param delimiter to split each element using (typically the equals symbol)
718: * @return a <code>Properties</code> instance representing the array contents,
719: * or <code>null</code> if the array to process was null or empty
720: */
721: public static Properties splitArrayElementsIntoProperties(
722: String[] array, String delimiter) {
723: return splitArrayElementsIntoProperties(array, delimiter, null);
724: }
725:
726: /**
727: * Take an array Strings and split each element based on the given delimiter.
728: * A <code>Properties</code> instance is then generated, with the left of the
729: * delimiter providing the key, and the right of the delimiter providing the value.
730: * <p>Will trim both the key and value before adding them to the
731: * <code>Properties</code> instance.
732: * @param array the array to process
733: * @param delimiter to split each element using (typically the equals symbol)
734: * @param charsToDelete one or more characters to remove from each element
735: * prior to attempting the split operation (typically the quotation mark
736: * symbol), or <code>null</code> if no removal should occur
737: * @return a <code>Properties</code> instance representing the array contents,
738: * or <code>null</code> if the array to process was <code>null</code> or empty
739: */
740: public static Properties splitArrayElementsIntoProperties(
741: String[] array, String delimiter, String charsToDelete) {
742:
743: if (ObjectUtils.isEmpty(array)) {
744: return null;
745: }
746: Properties result = new Properties();
747: for (int i = 0; i < array.length; i++) {
748: String element = array[i];
749: if (charsToDelete != null) {
750: element = deleteAny(array[i], charsToDelete);
751: }
752: String[] splittedElement = split(element, delimiter);
753: if (splittedElement == null) {
754: continue;
755: }
756: result.setProperty(splittedElement[0].trim(),
757: splittedElement[1].trim());
758: }
759: return result;
760: }
761:
762: /**
763: * Tokenize the given String into a String array via a StringTokenizer.
764: * Trims tokens and omits empty tokens.
765: * <p>The given delimiters string is supposed to consist of any number of
766: * delimiter characters. Each of those characters can be used to separate
767: * tokens. A delimiter is always a single character; for multi-character
768: * delimiters, consider using <code>delimitedListToStringArray</code>
769: * @param str the String to tokenize
770: * @param delimiters the delimiter characters, assembled as String
771: * (each of those characters is individually considered as delimiter).
772: * @return an array of the tokens
773: * @see java.util.StringTokenizer
774: * @see java.lang.String#trim()
775: * @see #delimitedListToStringArray
776: */
777: public static String[] tokenizeToStringArray(String str,
778: String delimiters) {
779: return tokenizeToStringArray(str, delimiters, true, true);
780: }
781:
782: /**
783: * Tokenize the given String into a String array via a StringTokenizer.
784: * <p>The given delimiters string is supposed to consist of any number of
785: * delimiter characters. Each of those characters can be used to separate
786: * tokens. A delimiter is always a single character; for multi-character
787: * delimiters, consider using <code>delimitedListToStringArray</code>
788: * @param str the String to tokenize
789: * @param delimiters the delimiter characters, assembled as String
790: * (each of those characters is individually considered as delimiter)
791: * @param trimTokens trim the tokens via String's <code>trim</code>
792: * @param ignoreEmptyTokens omit empty tokens from the result array
793: * (only applies to tokens that are empty after trimming; StringTokenizer
794: * will not consider subsequent delimiters as token in the first place).
795: * @return an array of the tokens (<code>null</code> if the input String
796: * was <code>null</code>)
797: * @see java.util.StringTokenizer
798: * @see java.lang.String#trim()
799: * @see #delimitedListToStringArray
800: */
801: public static String[] tokenizeToStringArray(String str,
802: String delimiters, boolean trimTokens,
803: boolean ignoreEmptyTokens) {
804:
805: if (str == null) {
806: return null;
807: }
808: StringTokenizer st = new StringTokenizer(str, delimiters);
809: List tokens = new ArrayList();
810: while (st.hasMoreTokens()) {
811: String token = st.nextToken();
812: if (trimTokens) {
813: token = token.trim();
814: }
815: if (!ignoreEmptyTokens || token.length() > 0) {
816: tokens.add(token);
817: }
818: }
819: return toStringArray(tokens);
820: }
821:
822: /**
823: * Take a String which is a delimited list and convert it to a String array.
824: * <p>A single delimiter can consists of more than one character: It will still
825: * be considered as single delimiter string, rather than as bunch of potential
826: * delimiter characters - in contrast to <code>tokenizeToStringArray</code>.
827: * @param str the input String
828: * @param delimiter the delimiter between elements (this is a single delimiter,
829: * rather than a bunch individual delimiter characters)
830: * @return an array of the tokens in the list
831: * @see #tokenizeToStringArray
832: */
833: public static String[] delimitedListToStringArray(String str,
834: String delimiter) {
835: if (str == null) {
836: return new String[0];
837: }
838: if (delimiter == null) {
839: return new String[] { str };
840: }
841: List result = new ArrayList();
842: if ("".equals(delimiter)) {
843: for (int i = 0; i < str.length(); i++) {
844: result.add(str.substring(i, i + 1));
845: }
846: } else {
847: int pos = 0;
848: int delPos = 0;
849: while ((delPos = str.indexOf(delimiter, pos)) != -1) {
850: result.add(str.substring(pos, delPos));
851: pos = delPos + delimiter.length();
852: }
853: if (str.length() > 0 && pos <= str.length()) {
854: // Add rest of String, but not in case of empty input.
855: result.add(str.substring(pos));
856: }
857: }
858: return toStringArray(result);
859: }
860:
861: /**
862: * Convert a CSV list into an array of Strings.
863: * @param str the input String
864: * @return an array of Strings, or the empty array in case of empty input
865: */
866: public static String[] commaDelimitedListToStringArray(String str) {
867: return delimitedListToStringArray(str, ",");
868: }
869:
870: /**
871: * Convenience method to convert a CSV string list to a set.
872: * Note that this will suppress duplicates.
873: * @param str the input String
874: * @return a Set of String entries in the list
875: */
876: public static Set commaDelimitedListToSet(String str) {
877: Set set = new TreeSet();
878: String[] tokens = commaDelimitedListToStringArray(str);
879: for (int i = 0; i < tokens.length; i++) {
880: set.add(tokens[i]);
881: }
882: return set;
883: }
884:
885: /**
886: * Convenience method to return a Collection as a delimited (e.g. CSV)
887: * String. E.g. useful for <code>toString()</code> implementations.
888: * @param coll the Collection to display
889: * @param delim the delimiter to use (probably a ",")
890: * @param prefix the String to start each element with
891: * @param suffix the String to end each element with
892: */
893: public static String collectionToDelimitedString(Collection coll,
894: String delim, String prefix, String suffix) {
895: if (CollectionUtils.isEmpty(coll)) {
896: return "";
897: }
898: StringBuffer sb = new StringBuffer();
899: Iterator it = coll.iterator();
900: while (it.hasNext()) {
901: sb.append(prefix).append(it.next()).append(suffix);
902: if (it.hasNext()) {
903: sb.append(delim);
904: }
905: }
906: return sb.toString();
907: }
908:
909: /**
910: * Convenience method to return a Collection as a delimited (e.g. CSV)
911: * String. E.g. useful for <code>toString()</code> implementations.
912: * @param coll the Collection to display
913: * @param delim the delimiter to use (probably a ",")
914: */
915: public static String collectionToDelimitedString(Collection coll,
916: String delim) {
917: return collectionToDelimitedString(coll, delim, "", "");
918: }
919:
920: /**
921: * Convenience method to return a Collection as a CSV String.
922: * E.g. useful for <code>toString()</code> implementations.
923: * @param coll the Collection to display
924: */
925: public static String collectionToCommaDelimitedString(
926: Collection coll) {
927: return collectionToDelimitedString(coll, ",");
928: }
929:
930: /**
931: * Convenience method to return a String array as a delimited (e.g. CSV)
932: * String. E.g. useful for <code>toString()</code> implementations.
933: * @param arr the array to display
934: * @param delim the delimiter to use (probably a ",")
935: */
936: public static String arrayToDelimitedString(Object[] arr,
937: String delim) {
938: if (ObjectUtils.isEmpty(arr)) {
939: return "";
940: }
941: StringBuffer sb = new StringBuffer();
942: for (int i = 0; i < arr.length; i++) {
943: if (i > 0) {
944: sb.append(delim);
945: }
946: sb.append(arr[i]);
947: }
948: return sb.toString();
949: }
950:
951: /**
952: * Convenience method to return a String array as a CSV String.
953: * E.g. useful for <code>toString()</code> implementations.
954: * @param arr the array to display
955: */
956: public static String arrayToCommaDelimitedString(Object[] arr) {
957: return arrayToDelimitedString(arr, ",");
958: }
959:
960: }
|