Package: StringUtils

StringUtils

nameinstructionbranchcomplexitylinemethod
StringUtils()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
abbreviateDotSeparatedString(String, int)
M: 82 C: 6
7%
M: 11 C: 1
8%
M: 6 C: 1
14%
M: 16 C: 2
11%
M: 0 C: 1
100%
addStringToArray(String[], String)
M: 0 C: 30
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
applyRelativePath(String, String)
M: 36 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
arrayToCommaDelimitedString(Object[])
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
arrayToDelimitedString(Object[], String)
M: 2 C: 30
94%
M: 1 C: 5
83%
M: 1 C: 3
75%
M: 1 C: 7
88%
M: 0 C: 1
100%
capitalize(String)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
changeFirstCharacterCase(String, boolean)
M: 0 C: 39
100%
M: 1 C: 5
83%
M: 1 C: 3
75%
M: 0 C: 9
100%
M: 0 C: 1
100%
chunkString(String, int)
M: 0 C: 55
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
cleanPath(String)
M: 2 C: 109
98%
M: 1 C: 15
94%
M: 1 C: 8
89%
M: 1 C: 26
96%
M: 0 C: 1
100%
collectionToCommaDelimitedString(Collection)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
collectionToDelimitedString(Collection, String)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
collectionToDelimitedString(Collection, String, String, String)
M: 2 C: 33
94%
M: 1 C: 5
83%
M: 1 C: 3
75%
M: 1 C: 8
89%
M: 0 C: 1
100%
commaDelimitedListToSet(String)
M: 23 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
commaDelimitedListToStringArray(String)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
concatenateStringArrays(String[], String[])
M: 0 C: 34
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 8
100%
M: 0 C: 1
100%
containsWhitespace(CharSequence)
M: 0 C: 24
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 7
100%
M: 0 C: 1
100%
containsWhitespace(String)
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
countOccurrencesOf(String, String)
M: 0 C: 35
100%
M: 1 C: 9
90%
M: 1 C: 5
83%
M: 0 C: 7
100%
M: 0 C: 1
100%
delete(String, String)
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
deleteAny(String, String)
M: 0 C: 36
100%
M: 0 C: 8
100%
M: 0 C: 5
100%
M: 0 C: 8
100%
M: 0 C: 1
100%
delimitedListToStringArray(String, String)
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
delimitedListToStringArray(String, String, String)
M: 0 C: 87
100%
M: 1 C: 13
93%
M: 1 C: 7
88%
M: 0 C: 17
100%
M: 0 C: 1
100%
endsWithIgnoreCase(String, String)
M: 0 C: 35
100%
M: 0 C: 8
100%
M: 0 C: 5
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
getFilename(String)
M: 0 C: 19
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
getFilenameExtension(String)
M: 0 C: 19
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
hasLength(CharSequence)
M: 0 C: 9
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
hasLength(String)
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
hasText(CharSequence)
M: 0 C: 24
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 7
100%
M: 0 C: 1
100%
hasText(String)
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
mergeStringArrays(String[], String[])
M: 0 C: 42
100%
M: 0 C: 8
100%
M: 0 C: 5
100%
M: 0 C: 11
100%
M: 0 C: 1
100%
parseLocaleString(String)
M: 0 C: 63
100%
M: 0 C: 10
100%
M: 0 C: 6
100%
M: 0 C: 10
100%
M: 0 C: 1
100%
pathEquals(String, String)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
quote(String)
M: 0 C: 14
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
quoteIfString(Object)
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
removeDuplicateStrings(String[])
M: 2 C: 24
92%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 1 C: 5
83%
M: 0 C: 1
100%
replace(String, String, String)
M: 0 C: 55
100%
M: 1 C: 7
88%
M: 1 C: 4
80%
M: 0 C: 15
100%
M: 0 C: 1
100%
sortStringArray(String[])
M: 3 C: 7
70%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 1 C: 3
75%
M: 0 C: 1
100%
split(String, String)
M: 4 C: 35
90%
M: 3 C: 3
50%
M: 3 C: 1
25%
M: 2 C: 6
75%
M: 0 C: 1
100%
splitArrayElementsIntoProperties(String[], String)
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
splitArrayElementsIntoProperties(String[], String, String)
M: 3 C: 46
94%
M: 2 C: 6
75%
M: 2 C: 3
60%
M: 2 C: 10
83%
M: 0 C: 1
100%
startsWithIgnoreCase(String, String)
M: 0 C: 33
100%
M: 0 C: 8
100%
M: 0 C: 5
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
stripFilenameExtension(String)
M: 0 C: 18
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
substringMatch(CharSequence, int, CharSequence)
M: 0 C: 34
100%
M: 0 C: 10
100%
M: 0 C: 6
100%
M: 0 C: 7
100%
M: 0 C: 1
100%
toLanguageTag(Locale)
M: 23 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
toStringArray(Collection)
M: 2 C: 9
82%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 1 C: 2
67%
M: 0 C: 1
100%
toStringArray(Enumeration)
M: 14 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
tokenizeToStringArray(String, String)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
tokenizeToStringArray(String, String, boolean, boolean)
M: 2 C: 36
95%
M: 1 C: 9
90%
M: 1 C: 5
83%
M: 1 C: 10
91%
M: 0 C: 1
100%
trimAllWhitespace(String)
M: 0 C: 31
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 10
100%
M: 0 C: 1
100%
trimArrayElements(String[])
M: 33 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
trimLeadingCharacter(String, char)
M: 0 C: 26
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
trimLeadingWhitespace(String)
M: 0 C: 26
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
trimTrailingCharacter(String, char)
M: 0 C: 32
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
trimTrailingWhitespace(String)
M: 0 C: 32
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
trimWhitespace(String)
M: 0 C: 45
100%
M: 0 C: 10
100%
M: 0 C: 6
100%
M: 0 C: 8
100%
M: 0 C: 1
100%
uncapitalize(String)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
unqualify(String)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
unqualify(String, char)
M: 0 C: 8
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2008, 2010 VMware Inc.
3: * All rights reserved. This program and the accompanying materials
4: * are made available under the terms of the Eclipse Public License v1.0
5: * which accompanies this distribution, and is available at
6: * http://www.eclipse.org/legal/epl-v10.html
7: *
8: * Contributors:
9: * VMware Inc. - initial contribution
10: *******************************************************************************/
11:
12: package org.eclipse.virgo.util.common;
13:
14: import java.util.ArrayList;
15: import java.util.Arrays;
16: import java.util.Collection;
17: import java.util.Collections;
18: import java.util.Enumeration;
19: import java.util.Iterator;
20: import java.util.LinkedList;
21: import java.util.List;
22: import java.util.Locale;
23: import java.util.Properties;
24: import java.util.Set;
25: import java.util.StringTokenizer;
26: import java.util.TreeSet;
27:
28: /**
29: * Miscellaneous {@link String} utility methods.
30: *
31: */
32: public abstract class StringUtils {
33:
34:         private static final String PREFIX_SEPARATOR = ":";
35:
36: private static final String FOLDER_SEPARATOR = "/";
37:
38:         private static final String WINDOWS_FOLDER_SEPARATOR = "\\";
39:
40:         private static final String TOP_PATH = "..";
41:
42:         private static final String CURRENT_PATH = ".";
43:
44:         private static final char EXTENSION_SEPARATOR = '.';
45:         
46:         private static final String DOT_SEPARATOR = ".";
47:
48: private static final String DOT_SEPARATOR_SPLIT_REGEX = "\\.";
49:
50:         //---------------------------------------------------------------------
51:         // General convenience methods for working with Strings
52:         //---------------------------------------------------------------------
53:
54:         /**
55:          * Check that the given CharSequence is neither <code>null</code> nor of length 0.
56:          * Note: Will return <code>true</code> for a CharSequence that purely consists of whitespace.
57:          * <p><pre>
58:          * StringUtils.hasLength(null) = false
59:          * StringUtils.hasLength("") = false
60:          * StringUtils.hasLength(" ") = true
61:          * StringUtils.hasLength("Hello") = true
62:          * </pre>
63:          * @param str the CharSequence to check (may be <code>null</code>)
64:          * @return <code>true</code> if the CharSequence is not null and has length
65:          * @see #hasText(String)
66:          */
67:         public static boolean hasLength(CharSequence str) {
68:•                return (str != null && str.length() > 0);
69:         }
70:
71:         /**
72:          * Check that the given String is neither <code>null</code> nor of length 0.
73:          * Note: Will return <code>true</code> for a String that purely consists of whitespace.
74:          * @param str the String to check (may be <code>null</code>)
75:          * @return <code>true</code> if the String is not null and has length
76:          * @see #hasLength(CharSequence)
77:          */
78:         public static boolean hasLength(String str) {
79:                 return hasLength((CharSequence) str);
80:         }
81:
82:         /**
83:          * Check whether the given CharSequence has actual text.
84:          * More specifically, returns <code>true</code> if the string not <code>null</code>,
85:          * its length is greater than 0, and it contains at least one non-whitespace character.
86:          * <p><pre>
87:          * StringUtils.hasText(null) = false
88:          * StringUtils.hasText("") = false
89:          * StringUtils.hasText(" ") = false
90:          * StringUtils.hasText("12345") = true
91:          * StringUtils.hasText(" 12345 ") = true
92:          * </pre>
93:          * @param str the CharSequence to check (may be <code>null</code>)
94:          * @return <code>true</code> if the CharSequence is not <code>null</code>,
95:          * its length is greater than 0, and it does not contain whitespace only
96:          * @see java.lang.Character#isWhitespace
97:          */
98:         public static boolean hasText(CharSequence str) {
99:•                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 has actual text.
113:          * More specifically, returns <code>true</code> if the string not <code>null</code>,
114:          * its length is greater than 0, and it contains at least one non-whitespace character.
115:          * @param str the String to check (may be <code>null</code>)
116:          * @return <code>true</code> if the String is not <code>null</code>, its length is
117:          * greater than 0, and it does not contain whitespace only
118:          * @see #hasText(CharSequence)
119:          */
120:         public static boolean hasText(String str) {
121:                 return hasText((CharSequence) str);
122:         }
123:
124:         /**
125:          * Check whether the given CharSequence contains any whitespace characters.
126:          * @param str the CharSequence to check (may be <code>null</code>)
127:          * @return <code>true</code> if the CharSequence is not empty and
128:          * contains at least 1 whitespace character
129:          * @see java.lang.Character#isWhitespace
130:          */
131:         public static boolean containsWhitespace(CharSequence str) {
132:•                if (!hasLength(str)) {
133:                         return false;
134:                 }
135:                 int strLen = str.length();
136:•                for (int i = 0; i < strLen; i++) {
137:•                        if (Character.isWhitespace(str.charAt(i))) {
138:                                 return true;
139:                         }
140:                 }
141:                 return false;
142:         }
143:
144:         /**
145:          * Check whether the given String contains any whitespace characters.
146:          * @param str the String to check (may be <code>null</code>)
147:          * @return <code>true</code> if the String is not empty and
148:          * contains at least 1 whitespace character
149:          * @see #containsWhitespace(CharSequence)
150:          */
151:         public static boolean containsWhitespace(String str) {
152:                 return containsWhitespace((CharSequence) str);
153:         }
154:
155:         /**
156:          * Trim leading and trailing whitespace from the given String.
157:          * @param str the String to check
158:          * @return the trimmed String
159:          * @see java.lang.Character#isWhitespace
160:          */
161:         public static String trimWhitespace(String str) {
162:•                if (!hasLength(str)) {
163:                         return str;
164:                 }
165:                 StringBuffer buf = new StringBuffer(str);
166:•                while (buf.length() > 0 && Character.isWhitespace(buf.charAt(0))) {
167:                         buf.deleteCharAt(0);
168:                 }
169:•                while (buf.length() > 0 && Character.isWhitespace(buf.charAt(buf.length() - 1))) {
170:                         buf.deleteCharAt(buf.length() - 1);
171:                 }
172:                 return buf.toString();
173:         }
174:
175:         /**
176:          * Trim <i>all</i> whitespace from the given String:
177:          * leading, trailing, and inbetween characters.
178:          * @param str the String to check
179:          * @return the trimmed String
180:          * @see java.lang.Character#isWhitespace
181:          */
182:         public static String trimAllWhitespace(String str) {
183:•                if (!hasLength(str)) {
184:                         return str;
185:                 }
186:                 StringBuffer buf = new StringBuffer(str);
187:                 int index = 0;
188:•                while (buf.length() > index) {
189:•                        if (Character.isWhitespace(buf.charAt(index))) {
190:                                 buf.deleteCharAt(index);
191:                         }
192:                         else {
193:                                 index++;
194:                         }
195:                 }
196:                 return buf.toString();
197:         }
198:
199:         /**
200:          * Trim leading whitespace from the given String.
201:          * @param str the String to check
202:          * @return the trimmed String
203:          * @see java.lang.Character#isWhitespace
204:          */
205:         public static String trimLeadingWhitespace(String str) {
206:•                if (!hasLength(str)) {
207:                         return str;
208:                 }
209:                 StringBuffer buf = new StringBuffer(str);
210:•                while (buf.length() > 0 && Character.isWhitespace(buf.charAt(0))) {
211:                         buf.deleteCharAt(0);
212:                 }
213:                 return buf.toString();
214:         }
215:
216:         /**
217:          * Trim trailing whitespace from the given String.
218:          * @param str the String to check
219:          * @return the trimmed String
220:          * @see java.lang.Character#isWhitespace
221:          */
222:         public static String trimTrailingWhitespace(String str) {
223:•                if (!hasLength(str)) {
224:                         return str;
225:                 }
226:                 StringBuffer buf = new StringBuffer(str);
227:•                while (buf.length() > 0 && Character.isWhitespace(buf.charAt(buf.length() - 1))) {
228:                         buf.deleteCharAt(buf.length() - 1);
229:                 }
230:                 return buf.toString();
231:         }
232:
233:         /**
234:          * Trim all occurences of the supplied leading character from the given String.
235:          * @param str the String to check
236:          * @param leadingCharacter the leading character to be trimmed
237:          * @return the trimmed String
238:          */
239:         public static String trimLeadingCharacter(String str, char leadingCharacter) {
240:•                if (!hasLength(str)) {
241:                         return str;
242:                 }
243:                 StringBuffer buf = new StringBuffer(str);
244:•                while (buf.length() > 0 && buf.charAt(0) == leadingCharacter) {
245:                         buf.deleteCharAt(0);
246:                 }
247:                 return buf.toString();
248:         }
249:
250:         /**
251:          * Trim all occurences of the supplied trailing character from the given String.
252:          * @param str the String to check
253:          * @param trailingCharacter the trailing character to be trimmed
254:          * @return the trimmed String
255:          */
256:         public static String trimTrailingCharacter(String str, char trailingCharacter) {
257:•                if (!hasLength(str)) {
258:                         return str;
259:                 }
260:                 StringBuffer buf = new StringBuffer(str);
261:•                while (buf.length() > 0 && buf.charAt(buf.length() - 1) == trailingCharacter) {
262:                         buf.deleteCharAt(buf.length() - 1);
263:                 }
264:                 return buf.toString();
265:         }
266:
267:
268:         /**
269:          * Test if the given String starts with the specified prefix,
270:          * ignoring upper/lower case.
271:          * @param str the String to check
272:          * @param prefix the prefix to look for
273:          * @return true if starts with prefix, without regard to case
274:          * @see java.lang.String#startsWith
275:          */
276:         public static boolean startsWithIgnoreCase(String str, String prefix) {
277:•                if (str == null || prefix == null) {
278:                         return false;
279:                 }
280:•                if (str.startsWith(prefix)) {
281:                         return true;
282:                 }
283:•                if (str.length() < prefix.length()) {
284:                         return false;
285:                 }
286:                 String lcStr = str.substring(0, prefix.length()).toLowerCase();
287:                 String lcPrefix = prefix.toLowerCase();
288:                 return lcStr.equals(lcPrefix);
289:         }
290:
291:         /**
292:          * Test if the given String ends with the specified suffix,
293:          * ignoring upper/lower case.
294:          * @param str the String to check
295:          * @param suffix the suffix to look for
296: * @return true if ends with suffix, without regard to case
297:          * @see java.lang.String#endsWith
298:          */
299:         public static boolean endsWithIgnoreCase(String str, String suffix) {
300:•                if (str == null || suffix == null) {
301:                         return false;
302:                 }
303:•                if (str.endsWith(suffix)) {
304:                         return true;
305:                 }
306:•                if (str.length() < suffix.length()) {
307:                         return false;
308:                 }
309:
310:                 String lcStr = str.substring(str.length() - suffix.length()).toLowerCase();
311:                 String lcSuffix = suffix.toLowerCase();
312:                 return lcStr.equals(lcSuffix);
313:         }
314:
315:         /**
316:          * Test whether the given string matches the given substring
317:          * at the given index.
318:          * @param str the original string (or StringBuffer)
319:          * @param index the index in the original string to start matching against
320:          * @param substring the substring to match at the given index
321:          * @return true if a match
322:          */
323:         public static boolean substringMatch(CharSequence str, int index, CharSequence substring) {
324:•         if (index < 0 && substring.length() > 0) {
325:          return false;
326:          }
327:•                for (int j = 0; j < substring.length(); j++) {
328:                         int i = index + j;
329:•                        if (i >= str.length() || str.charAt(i) != substring.charAt(j)) {
330:                                 return false;
331:                         }
332:                 }
333:                 return true;
334:         }
335:
336:         /**
337:          * Count the occurrences of the substring in string s.
338:          * @param str string to search in. Return 0 if this is null.
339:          * @param sub string to search for. Return 0 if this is null.
340:          * @return count
341:          */
342:         public static int countOccurrencesOf(String str, String sub) {
343:•                if (str == null || sub == null || str.length() == 0 || sub.length() == 0) {
344:                         return 0;
345:                 }
346:                 int count = 0, pos = 0, idx = 0;
347:•                while ((idx = str.indexOf(sub, pos)) != -1) {
348:                         ++count;
349:                         pos = idx + sub.length();
350:                 }
351:                 return count;
352:         }
353:
354:         /**
355:          * Replace all occurences of a substring within a string with
356:          * another string.
357:          * @param inString String to examine
358:          * @param oldPattern String to replace
359:          * @param newPattern String to insert
360:          * @return a String with the replacements
361:          */
362:         public static String replace(String inString, String oldPattern, String newPattern) {
363:•                if (inString == null) {
364:                         return null;
365:                 }
366:•                if (oldPattern == null || newPattern == null) {
367:                         return inString;
368:                 }
369:
370:                 StringBuffer sbuf = new StringBuffer();
371:                 // output StringBuffer we'll build up
372:                 int pos = 0; // our position in the old string
373:                 int index = inString.indexOf(oldPattern);
374:                 // the index of an occurrence we've found, or -1
375:                 int patLen = oldPattern.length();
376:•                while (index >= 0) {
377:                         sbuf.append(inString.substring(pos, index));
378:                         sbuf.append(newPattern);
379:                         pos = index + patLen;
380:                         index = inString.indexOf(oldPattern, pos);
381:                 }
382:                 sbuf.append(inString.substring(pos));
383:
384:                 // remember to append any characters to the right of a match
385:                 return sbuf.toString();
386:         }
387:
388:         /**
389:          * Delete all occurrences of the given substring.
390:          * @param inString the original String
391:          * @param pattern the pattern to delete all occurrences of
392:          * @return the resulting String
393:          */
394:         public static String delete(String inString, String pattern) {
395:                 return replace(inString, pattern, "");
396:         }
397:
398:         /**
399:          * Delete any character in a given String.
400:          * @param inString the original String
401:          * @param charsToDelete a set of characters to delete.
402:          * E.g. "az\n" will delete 'a's, 'z's and new lines.
403:          * @return the resulting String
404:          */
405:         public static String deleteAny(String inString, String charsToDelete) {
406:•                if (!hasLength(inString) || !hasLength(charsToDelete)) {
407:                         return inString;
408:                 }
409:                 StringBuffer out = new StringBuffer();
410:•                for (int i = 0; i < inString.length(); i++) {
411:                         char c = inString.charAt(i);
412:•                        if (charsToDelete.indexOf(c) == -1) {
413:                                 out.append(c);
414:                         }
415:                 }
416:                 return out.toString();
417:         }
418:
419:
420:         //---------------------------------------------------------------------
421:         // Convenience methods for working with formatted Strings
422:         //---------------------------------------------------------------------
423:
424:         /**
425:          * Quote the given String with single quotes.
426:          * @param str the input String (e.g. "myString")
427:          * @return the quoted String (e.g. "'myString'"),
428:          * or <code>null<code> if the input was <code>null</code>
429:          */
430:         public static String quote(String str) {
431:•                return (str != null ? "'" + str + "'" : null);
432:         }
433:
434:         /**
435:          * Turn the given Object into a String with single quotes
436:          * if it is a String; keeping the Object as-is else.
437:          * @param obj the input Object (e.g. "myString")
438:          * @return the quoted String (e.g. "'myString'"),
439:          * or the input object as-is if not a String
440:          */
441:         public static Object quoteIfString(Object obj) {
442:•                return (obj instanceof String ? quote((String) obj) : obj);
443:         }
444:
445:         /**
446:          * Unqualify a string qualified by a '.' dot character. For example,
447:          * "this.name.is.qualified", returns "qualified".
448:          * @param qualifiedName the qualified name
449:          * @return unqualified name
450:          */
451:         public static String unqualify(String qualifiedName) {
452:                 return unqualify(qualifiedName, '.');
453:         }
454:
455:         /**
456:          * Unqualify a string qualified by a separator character. For example,
457:          * "this:name:is:qualified" returns "qualified" if using a ':' separator.
458:          * @param qualifiedName the qualified name
459:          * @param separator the separator
460:          * @return unqualified name
461:          */
462:         public static String unqualify(String qualifiedName, char separator) {
463:                 return qualifiedName.substring(qualifiedName.lastIndexOf(separator) + 1);
464:         }
465:
466:         /**
467:          * Capitalize a <code>String</code>, changing the first letter to
468:          * upper case as per {@link Character#toUpperCase(char)}.
469:          * No other letters are changed.
470:          * @param str the String to capitalize, may be <code>null</code>
471:          * @return the capitalized String, <code>null</code> if null
472:          */
473:         public static String capitalize(String str) {
474:                 return changeFirstCharacterCase(str, true);
475:         }
476:
477:         /**
478:          * Uncapitalize a <code>String</code>, changing the first letter to
479:          * lower case as per {@link Character#toLowerCase(char)}.
480:          * No other letters are changed.
481:          * @param str the String to uncapitalize, may be <code>null</code>
482:          * @return the uncapitalized String, <code>null</code> if null
483:          */
484:         public static String uncapitalize(String str) {
485:                 return changeFirstCharacterCase(str, false);
486:         }
487:
488:         private static String changeFirstCharacterCase(String str, boolean capitalize) {
489:•                if (str == null || str.length() == 0) {
490:                         return str;
491:                 }
492:                 StringBuffer buf = new StringBuffer(str.length());
493:•                if (capitalize) {
494:                         buf.append(Character.toUpperCase(str.charAt(0)));
495:                 }
496:                 else {
497:                         buf.append(Character.toLowerCase(str.charAt(0)));
498:                 }
499:                 buf.append(str.substring(1));
500:                 return buf.toString();
501:         }
502:
503:         /**
504:          * Extract the filename from the given path,
505:          * e.g. "mypath/myfile.txt" -> "myfile.txt".
506:          * @param path the file path (may be <code>null</code>)
507:          * @return the extracted filename, or <code>null</code> if none
508:          */
509:         public static String getFilename(String path) {
510:•                if (path == null) {
511:                         return null;
512:                 }
513:                 int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR);
514:•                return (separatorIndex != -1 ? path.substring(separatorIndex + 1) : path);
515:         }
516:
517:         /**
518:          * Extract the filename extension from the given path,
519:          * e.g. "mypath/myfile.txt" -> "txt".
520:          * @param path the file path (may be <code>null</code>)
521:          * @return the extracted filename extension, or <code>null</code> if none
522:          */
523:         public static String getFilenameExtension(String path) {
524:•                if (path == null) {
525:                         return null;
526:                 }
527:                 int sepIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
528:•                return (sepIndex != -1 ? path.substring(sepIndex + 1) : null);
529:         }
530:
531:         /**
532:          * Strip the filename extension from the given path,
533:          * e.g. "mypath/myfile.txt" -> "mypath/myfile".
534:          * @param path the file path (may be <code>null</code>)
535:          * @return the path with stripped filename extension,
536:          * or <code>null</code> if none
537:          */
538:         public static String stripFilenameExtension(String path) {
539:•                if (path == null) {
540:                         return null;
541:                 }
542:                 int sepIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
543:•                return (sepIndex != -1 ? path.substring(0, sepIndex) : path);
544:         }
545:
546:         /**
547:          * Apply the given relative path to the given path,
548:          * assuming standard Java folder separation (i.e. "/" separators);
549:          * @param path the path to start from (usually a full file path)
550:          * @param relativePath the relative path to apply
551:          * (relative to the full file path above)
552:          * @return the full file path that results from applying the relative path
553:          */
554:         public static String applyRelativePath(String path, String relativePath) {
555:                 int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR);
556:•                if (separatorIndex != -1) {
557:                         String newPath = path.substring(0, separatorIndex);
558:•                        if (!relativePath.startsWith(FOLDER_SEPARATOR)) {
559:                                 newPath += FOLDER_SEPARATOR;
560:                         }
561:                         return newPath + relativePath;
562:                 }
563:                 else {
564:                         return relativePath;
565:                 }
566:         }
567:
568:         /**
569:          * Normalize the path by suppressing sequences like "path/.." and
570:          * inner simple dots.
571:          * <p>The result is convenient for path comparison. For other uses,
572:          * notice that Windows separators ("\") are replaced by simple slashes.
573:          * @param path the original path
574:          * @return the normalized path
575:          */
576:         public static String cleanPath(String path) {
577:•                if (path == null) {
578:                         return null;
579:                 }
580:                 String pathToUse = replace(path, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR);
581:
582:                 // Strip prefix from path to analyze, to not treat it as part of the
583:                 // first path element. This is necessary to correctly parse paths like
584:                 // "file:core/../core/io/Resource.class", where the ".." should just
585:                 // strip the first "core" directory while keeping the "file:" prefix.
586:                 int prefixIndex = pathToUse.indexOf(PREFIX_SEPARATOR);
587:                 String prefix = "";
588:•                if (prefixIndex != -1) {
589:                         prefix = pathToUse.substring(0, prefixIndex + 1);
590:                         pathToUse = pathToUse.substring(prefixIndex + 1);
591:                 }
592:•                if (pathToUse.startsWith(FOLDER_SEPARATOR)) {
593:                         prefix = prefix + FOLDER_SEPARATOR;
594:                         pathToUse = pathToUse.substring(1);
595:                 }
596:
597:                 String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR);
598:                 List<String> pathElements = new LinkedList<String>();
599:                 int tops = 0;
600:
601:•                for (int i = pathArray.length - 1; i >= 0; i--) {
602:                         String element = pathArray[i];
603:•                        if (CURRENT_PATH.equals(element)) {
604:                                 // Points to current directory - drop it.
605:                         }
606:•                        else if (TOP_PATH.equals(element)) {
607:                                 // Registering top path found.
608:                                 tops++;
609:                         }
610:                         else {
611:•                                if (tops > 0) {
612:                                         // Merging path element with element corresponding to top path.
613:                                         tops--;
614:                                 }
615:                                 else {
616:                                         // Normal path element found.
617:                                         pathElements.add(0, element);
618:                                 }
619:                         }
620:                 }
621:
622:                 // Remaining top paths need to be retained.
623:•                for (int i = 0; i < tops; i++) {
624:                         pathElements.add(0, TOP_PATH);
625:                 }
626:
627:                 return prefix + collectionToDelimitedString(pathElements, FOLDER_SEPARATOR);
628:         }
629:
630:         /**
631:          * Compare two paths after normalization of them.
632:          * @param path1 first path for comparison
633:          * @param path2 second path for comparison
634:          * @return whether the two paths are equivalent after normalization
635:          */
636:         public static boolean pathEquals(String path1, String path2) {
637:                 return cleanPath(path1).equals(cleanPath(path2));
638:         }
639:
640:         /**
641:          * Parse the given <code>localeString</code> into a {@link Locale}.
642:          * <p>This is the inverse operation of {@link Locale#toString Locale's toString}.
643:          * @param localeString the locale string, following <code>Locale's</code>
644:          * <code>toString()</code> format ("en", "en_UK", etc);
645:          * also accepts spaces as separators, as an alternative to underscores
646:          * @return a corresponding <code>Locale</code> instance
647:          */
648:         public static Locale parseLocaleString(String localeString) {
649:                 String[] parts = tokenizeToStringArray(localeString, "_ ", false, false);
650:•                String language = (parts.length > 0 ? parts[0] : "");
651:•                String country = (parts.length > 1 ? parts[1] : "");
652:                 String variant = "";
653:•                if (parts.length >= 2) {
654:                         // There is definitely a variant, and it is everything after the country
655:                         // code sans the separator between the country code and the variant.
656:                         int endIndexOfCountryCode = localeString.indexOf(country) + country.length();
657:                         // Strip off any leading '_' and whitespace, what's left is the variant.
658:                         variant = trimLeadingWhitespace(localeString.substring(endIndexOfCountryCode));
659:•                        if (variant.startsWith("_")) {
660:                                 variant = trimLeadingCharacter(variant, '_');
661:                         }
662:                 }
663:•                return (language.length() > 0 ? new Locale(language, country, variant) : null);
664:         }
665:
666:         /**
667:          * Determine the RFC 3066 compliant language tag,
668:          * as used for the HTTP "Accept-Language" header.
669:          * @param locale the Locale to transform to a language tag
670:          * @return the RFC 3066 compliant language tag as String
671:          */
672:         public static String toLanguageTag(Locale locale) {
673:•                return locale.getLanguage() + (hasText(locale.getCountry()) ? "-" + locale.getCountry() : "");
674:         }
675:
676:
677:         //---------------------------------------------------------------------
678:         // Convenience methods for working with String arrays
679:         //---------------------------------------------------------------------
680:
681:         /**
682:          * Append the given String to the given String array, returning a new array
683:          * consisting of the input array contents plus the given String.
684:          * @param array the array to append to (can be <code>null</code>)
685:          * @param str the String to append
686:          * @return the new array (never <code>null</code>)
687:          */
688:         public static String[] addStringToArray(String[] array, String str) {
689:•                if (ObjectUtils.isEmpty(array)) {
690:                         return new String[] {str};
691:                 }
692:                 String[] newArr = new String[array.length + 1];
693:                 System.arraycopy(array, 0, newArr, 0, array.length);
694:                 newArr[array.length] = str;
695:                 return newArr;
696:         }
697:
698:         /**
699:          * Concatenate the given String arrays into one,
700:          * with overlapping array elements included twice.
701:          * <p>The order of elements in the original arrays is preserved.
702:          * @param array1 the first array (can be <code>null</code>)
703:          * @param array2 the second array (can be <code>null</code>)
704:          * @return the new array (<code>null</code> if both given arrays were <code>null</code>)
705:          */
706:         public static String[] concatenateStringArrays(String[] array1, String[] array2) {
707:•                if (ObjectUtils.isEmpty(array1)) {
708:                         return array2;
709:                 }
710:•                if (ObjectUtils.isEmpty(array2)) {
711:                         return array1;
712:                 }
713:                 String[] newArr = new String[array1.length + array2.length];
714:                 System.arraycopy(array1, 0, newArr, 0, array1.length);
715:                 System.arraycopy(array2, 0, newArr, array1.length, array2.length);
716:                 return newArr;
717:         }
718:
719:         /**
720:          * Merge the given String arrays into one, with overlapping
721:          * array elements only included once.
722:          * <p>The order of elements in the original arrays is preserved
723:          * (with the exception of overlapping elements, which are only
724:          * included on their first occurence).
725:          * @param array1 the first array (can be <code>null</code>)
726:          * @param array2 the second array (can be <code>null</code>)
727:          * @return the new array (<code>null</code> if both given arrays were <code>null</code>)
728:          */
729:         public static String[] mergeStringArrays(String[] array1, String[] array2) {
730:•                if (ObjectUtils.isEmpty(array1)) {
731:                         return array2;
732:                 }
733:•                if (ObjectUtils.isEmpty(array2)) {
734:                         return array1;
735:                 }
736:                 List<String> result = new ArrayList<String>();
737:                 result.addAll(Arrays.asList(array1));
738:•                for (int i = 0; i < array2.length; i++) {
739:                         String str = array2[i];
740:•                        if (!result.contains(str)) {
741:                                 result.add(str);
742:                         }
743:                 }
744:                 return toStringArray(result);
745:         }
746:
747:         /**
748:          * Turn given source String array into sorted array.
749:          * @param array the source array
750:          * @return the sorted array (never <code>null</code>)
751:          */
752:         public static String[] sortStringArray(String[] array) {
753:•                if (ObjectUtils.isEmpty(array)) {
754:                         return new String[0];
755:                 }
756:                 Arrays.sort(array);
757:                 return array;
758:         }
759:
760:         /**
761:          * Copy the given Collection into a String array.
762:          * @param collection the Collection to copy
763:          * @return the String array (<code>null</code> if the passed-in
764:          * Collection was <code>null</code>)
765:          */
766:         public static String[] toStringArray(Collection<String> collection) {
767:•                if (collection == null) {
768:                         return null;
769:                 }
770:                 return (String[]) collection.toArray(new String[collection.size()]);
771:         }
772:
773:         /**
774:          * Copy the given Enumeration into a String array.
775:          * @param enumeration the Enumeration to copy
776:          * @return the String array (<code>null</code> if the passed-in
777:          * Enumeration was <code>null</code>)
778:          */
779:         public static String[] toStringArray(Enumeration<String> enumeration) {
780:•                if (enumeration == null) {
781:                         return null;
782:                 }
783:                 List<String> list = Collections.list(enumeration);
784:                 return (String[]) list.toArray(new String[list.size()]);
785:         }
786:
787:         /**
788:          * Trim the elements of the given String array,
789:          * calling <code>String.trim()</code> on each of them.
790:          * @param array the original String array
791:          * @return the resulting array (of the same size) with trimmed elements
792:          */
793:         public static String[] trimArrayElements(String[] array) {
794:•                if (ObjectUtils.isEmpty(array)) {
795:                         return new String[0];
796:                 }
797:                 String[] result = new String[array.length];
798:•                for (int i = 0; i < array.length; i++) {
799:                         String element = array[i];
800:•                        result[i] = (element != null ? element.trim() : null);
801:                 }
802:                 return result;
803:         }
804:
805:         /**
806:          * Remove duplicate Strings from the given array.
807:          * Also sorts the array, as it uses a TreeSet.
808:          * @param array the String array
809:          * @return an array without duplicates, in natural sort order
810:          */
811:         public static String[] removeDuplicateStrings(String[] array) {
812:•                if (ObjectUtils.isEmpty(array)) {
813:                         return array;
814:                 }
815:                 Set<String> set = new TreeSet<String>();
816:•                for (int i = 0; i < array.length; i++) {
817:                         set.add(array[i]);
818:                 }
819:                 return toStringArray(set);
820:         }
821:
822:         /**
823:          * Split a String at the first occurrence of the delimiter.
824:          * Does not include the delimiter in the result.
825:          * @param toSplit the string to split
826:          * @param delimiter to split the string up with
827:          * @return a two element array with index 0 being before the delimiter, and
828:          * index 1 being after the delimiter (neither element includes the delimiter);
829:          * or <code>null</code> if the delimiter wasn't found in the given input String
830:          */
831:         public static String[] split(String toSplit, String delimiter) {
832:•                if (!hasLength(toSplit) || !hasLength(delimiter)) {
833:                         return null;
834:                 }
835:                 int offset = toSplit.indexOf(delimiter);
836:•                if (offset < 0) {
837:                         return null;
838:                 }
839:                 String beforeDelimiter = toSplit.substring(0, offset);
840:                 String afterDelimiter = toSplit.substring(offset + delimiter.length());
841:                 return new String[] {beforeDelimiter, afterDelimiter};
842:         }
843:
844:         /**
845:          * Take an array Strings and split each element based on the given delimiter.
846:          * A <code>Properties</code> instance is then generated, with the left of the
847:          * delimiter providing the key, and the right of the delimiter providing the value.
848:          * <p>Will trim both the key and value before adding them to the
849:          * <code>Properties</code> instance.
850:          * @param array the array to process
851:          * @param delimiter to split each element using (typically the equals symbol)
852:          * @return a <code>Properties</code> instance representing the array contents,
853:          * or <code>null</code> if the array to process was null or empty
854:          */
855:         public static Properties splitArrayElementsIntoProperties(String[] array, String delimiter) {
856:                 return splitArrayElementsIntoProperties(array, delimiter, null);
857:         }
858:
859:         /**
860:          * Take an array Strings and split each element based on the given delimiter.
861:          * A <code>Properties</code> instance is then generated, with the left of the
862:          * delimiter providing the key, and the right of the delimiter providing the value.
863:          * <p>Will trim both the key and value before adding them to the
864:          * <code>Properties</code> instance.
865:          * @param array the array to process
866:          * @param delimiter to split each element using (typically the equals symbol)
867:          * @param charsToDelete one or more characters to remove from each element
868:          * prior to attempting the split operation (typically the quotation mark
869:          * symbol), or <code>null</code> if no removal should occur
870:          * @return a <code>Properties</code> instance representing the array contents,
871:          * or <code>null</code> if the array to process was <code>null</code> or empty
872:          */
873:         public static Properties splitArrayElementsIntoProperties(
874:                         String[] array, String delimiter, String charsToDelete) {
875:
876:•                if (ObjectUtils.isEmpty(array)) {
877:                         return null;
878:                 }
879:                 Properties result = new Properties();
880:•                for (int i = 0; i < array.length; i++) {
881:                         String element = array[i];
882:•                        if (charsToDelete != null) {
883:                                 element = deleteAny(array[i], charsToDelete);
884:                         }
885:                         String[] splittedElement = split(element, delimiter);
886:•                        if (splittedElement == null) {
887:                                 continue;
888:                         }
889:                         result.setProperty(splittedElement[0].trim(), splittedElement[1].trim());
890:                 }
891:                 return result;
892:         }
893:
894:         /**
895:          * Tokenize the given String into a String array via a StringTokenizer.
896:          * Trims tokens and omits empty tokens.
897:          * <p>The given delimiters string is supposed to consist of any number of
898:          * delimiter characters. Each of those characters can be used to separate
899:          * tokens. A delimiter is always a single character; for multi-character
900:          * delimiters, consider using <code>delimitedListToStringArray</code>
901:          * @param str the String to tokenize
902:          * @param delimiters the delimiter characters, assembled as String
903:          * (each of those characters is individually considered as delimiter).
904:          * @return an array of the tokens
905:          * @see java.util.StringTokenizer
906:          * @see java.lang.String#trim()
907:          * @see #delimitedListToStringArray
908:          */
909:         public static String[] tokenizeToStringArray(String str, String delimiters) {
910:                 return tokenizeToStringArray(str, delimiters, true, true);
911:         }
912:
913:         /**
914:          * Tokenize the given String into a String array via a StringTokenizer.
915:          * <p>The given delimiters string is supposed to consist of any number of
916:          * delimiter characters. Each of those characters can be used to separate
917:          * tokens. A delimiter is always a single character; for multi-character
918:          * delimiters, consider using <code>delimitedListToStringArray</code>
919:          * @param str the String to tokenize
920:          * @param delimiters the delimiter characters, assembled as String
921:          * (each of those characters is individually considered as delimiter)
922:          * @param trimTokens trim the tokens via String's <code>trim</code>
923:          * @param ignoreEmptyTokens omit empty tokens from the result array
924:          * (only applies to tokens that are empty after trimming; StringTokenizer
925:          * will not consider subsequent delimiters as token in the first place).
926:          * @return an array of the tokens (<code>null</code> if the input String
927:          * was <code>null</code>)
928:          * @see java.util.StringTokenizer
929:          * @see java.lang.String#trim()
930:          * @see #delimitedListToStringArray
931:          */
932:         public static String[] tokenizeToStringArray(
933:                         String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) {
934:
935:•                if (str == null) {
936:                         return null;
937:                 }
938:                 StringTokenizer st = new StringTokenizer(str, delimiters);
939:                 List<String> tokens = new ArrayList<String>();
940:•                while (st.hasMoreTokens()) {
941:                         String token = st.nextToken();
942:•                        if (trimTokens) {
943:                                 token = token.trim();
944:                         }
945:•                        if (!ignoreEmptyTokens || token.length() > 0) {
946:                                 tokens.add(token);
947:                         }
948:                 }
949:                 return toStringArray(tokens);
950:         }
951:
952:         /**
953:          * Take a String which is a delimited list and convert it to a String array.
954:          * <p>A single delimiter can consists of more than one character: It will still
955:          * be considered as single delimiter string, rather than as bunch of potential
956:          * delimiter characters - in contrast to <code>tokenizeToStringArray</code>.
957:          * @param str the input String
958:          * @param delimiter the delimiter between elements (this is a single delimiter,
959:          * rather than a bunch individual delimiter characters)
960:          * @return an array of the tokens in the list
961:          * @see #tokenizeToStringArray
962:          */
963:         public static String[] delimitedListToStringArray(String str, String delimiter) {
964:                 return delimitedListToStringArray(str, delimiter, null);
965:         }
966:
967:         /**
968:          * Take a String which is a delimited list and convert it to a String array.
969:          * <p>A single delimiter can consists of more than one character: It will still
970:          * be considered as single delimiter string, rather than as bunch of potential
971:          * delimiter characters - in contrast to <code>tokenizeToStringArray</code>.
972:          * @param str the input String
973:          * @param delimiter the delimiter between elements (this is a single delimiter,
974:          * rather than a bunch individual delimiter characters)
975:          * @param charsToDelete a set of characters to delete. Useful for deleting unwanted
976:          * line breaks: e.g. "\r\n\f" will delete all new lines and line feeds in a String.
977:          * @return an array of the tokens in the list
978:          * @see #tokenizeToStringArray
979:          */
980:         public static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) {
981:•                if (str == null) {
982:                         return new String[0];
983:                 }
984:•                if (delimiter == null) {
985:                         return new String[] {str};
986:                 }
987:                 List<String> result = new ArrayList<String>();
988:•                if ("".equals(delimiter)) {
989:•                        for (int i = 0; i < str.length(); i++) {
990:                                 result.add(deleteAny(str.substring(i, i + 1), charsToDelete));
991:                         }
992:                 }
993:                 else {
994:                         int pos = 0;
995:                         int delPos = 0;
996:•                        while ((delPos = str.indexOf(delimiter, pos)) != -1) {
997:                                 result.add(deleteAny(str.substring(pos, delPos), charsToDelete));
998:                                 pos = delPos + delimiter.length();
999:                         }
1000:•                        if (str.length() > 0 && pos <= str.length()) {
1001:                                 // Add rest of String, but not in case of empty input.
1002:                                 result.add(deleteAny(str.substring(pos), charsToDelete));
1003:                         }
1004:                 }
1005:                 return toStringArray(result);
1006:         }
1007:
1008:         /**
1009:          * Convert a CSV list into an array of Strings.
1010:          * @param str the input String
1011:          * @return an array of Strings, or the empty array in case of empty input
1012:          */
1013:         public static String[] commaDelimitedListToStringArray(String str) {
1014:                 return delimitedListToStringArray(str, ",");
1015:         }
1016:
1017:         /**
1018:          * Convenience method to convert a CSV string list to a set.
1019:          * Note that this will suppress duplicates.
1020:          * @param str the input String
1021:          * @return a Set of String entries in the list
1022:          */
1023:         public static Set<String> commaDelimitedListToSet(String str) {
1024:                 Set<String> set = new TreeSet<String>();
1025:                 String[] tokens = commaDelimitedListToStringArray(str);
1026:•                for (int i = 0; i < tokens.length; i++) {
1027:                         set.add(tokens[i]);
1028:                 }
1029:                 return set;
1030:         }
1031:
1032:         /**
1033:          * Convenience method to return a Collection as a delimited (e.g. CSV)
1034:          * String. E.g. useful for <code>toString()</code> implementations.
1035:          * @param coll the Collection to display
1036:          * @param delim the delimiter to use (probably a ",")
1037:          * @param prefix the String to start each element with
1038:          * @param suffix the String to end each element with
1039:          * @return the delimited String
1040:          */
1041:         public static String collectionToDelimitedString(Collection<?> coll, String delim, String prefix, String suffix) {
1042:•                if (CollectionUtils.isEmpty(coll)) {
1043:                         return "";
1044:                 }
1045:                 StringBuffer sb = new StringBuffer();
1046:                 Iterator<?> it = coll.iterator();
1047:•                while (it.hasNext()) {
1048:                         sb.append(prefix).append(it.next()).append(suffix);
1049:•                        if (it.hasNext()) {
1050:                                 sb.append(delim);
1051:                         }
1052:                 }
1053:                 return sb.toString();
1054:         }
1055:
1056:         /**
1057:          * Convenience method to return a Collection as a delimited (e.g. CSV)
1058:          * String. E.g. useful for <code>toString()</code> implementations.
1059:          * @param coll the Collection to display
1060:          * @param delim the delimiter to use (probably a ",")
1061:          * @return the delimited String
1062:          */
1063:         public static String collectionToDelimitedString(Collection<?> coll, String delim) {
1064:                 return collectionToDelimitedString(coll, delim, "", "");
1065:         }
1066:
1067:         /**
1068:          * Convenience method to return a Collection as a CSV String.
1069:          * E.g. useful for <code>toString()</code> implementations.
1070:          * @param coll the Collection to display
1071:          * @return the delimited String
1072:          */
1073:         public static String collectionToCommaDelimitedString(Collection<?> coll) {
1074:                 return collectionToDelimitedString(coll, ",");
1075:         }
1076:
1077:         /**
1078:          * Convenience method to return a String array as a delimited (e.g. CSV)
1079:          * String. E.g. useful for <code>toString()</code> implementations.
1080:          * @param arr the array to display
1081:          * @param delim the delimiter to use (probably a ",")
1082:          * @return the delimited String
1083:          */
1084:         public static String arrayToDelimitedString(Object[] arr, String delim) {
1085:•                if (ObjectUtils.isEmpty(arr)) {
1086:                         return "";
1087:                 }
1088:                 StringBuffer sb = new StringBuffer();
1089:•                for (int i = 0; i < arr.length; i++) {
1090:•                        if (i > 0) {
1091:                                 sb.append(delim);
1092:                         }
1093:                         sb.append(arr[i]);
1094:                 }
1095:                 return sb.toString();
1096:         }
1097:
1098:         /**
1099:          * Convenience method to return a String array as a CSV String.
1100:          * E.g. useful for <code>toString()</code> implementations.
1101:          * @param arr the array to display
1102:          * @return the delimited String
1103:          */
1104:         public static String arrayToCommaDelimitedString(Object[] arr) {
1105:                 return arrayToDelimitedString(arr, ",");
1106:         }
1107:         
1108: /**
1109: * Divides <code>input</code> into one or more chunks, each of the
1110: * supplied <code>chunkLength</code>, other than the last chunk
1111: * which will be up to <code>chunkLength</code> characters long.
1112: * <p/>
1113: * The <code>chunkLength</code> must be greater than zero.
1114: *
1115: * @param input The <code>String</code> to chunk
1116: * @param chunkLength The length of the chunks
1117: * @throws IllegalArgumentException If the supplied <code>chunkLength</code>
1118: * is not greater than zero
1119: * @return The chunks
1120: */
1121:         public static String[] chunkString(String input, int chunkLength) {
1122:• if (chunkLength < 1) {
1123: throw new IllegalArgumentException("Chunk length must be greater than zero");
1124: }
1125:
1126:• if (input.length() <= chunkLength) {
1127: return new String[] {input};
1128: }
1129:
1130: List<String> chunks = new ArrayList<String>();
1131:
1132:• for (int i = 0; i < input.length(); i += chunkLength) {
1133: int end = Math.min(i + chunkLength, input.length());
1134: chunks.add(input.substring(i, end));
1135: }
1136:
1137: return chunks.toArray(new String[chunks.size()]);
1138: }
1139:                 
1140: /**
1141: * Abbreviates the given dot-separated string to reduce its length (if necessary) to within the supplied target
1142: * length.
1143: *
1144: * <p />
1145: *
1146: * The abbreviation is performed by, starting with the left-most segment, replacing each segment in turn with its first
1147: * character until the length is equal to or less than the target. If this approach fails to sufficiently reduce the
1148: * string's length, the right-most segment is returned in its entirety, even if its length exceeds the target
1149: * length.
1150: *
1151: * <p />
1152: *
1153: * For example with the input alpha.bravo.charlie.Delta the following results are produced:
1154: * <table>
1155: * <tr><td>Target length</td><td>Result</td></tr>
1156: * <tr><td>32</td><td>alpha.bravo.charlie.Delta</td></tr>
1157: * <tr><td>21</td><td>a.bravo.charlie.Delta</td></tr>
1158: * <tr><td>17</td><td>a.b.charlie.Delta</td></tr>
1159: * <tr><td>12</td><td>a.b.c.Delta</td></tr>
1160: * <tr><td>10</td><td>Delta</td></tr>
1161: * </table>
1162: *
1163: * @param string The String to abbreviate
1164: * @param targetLength The target length for the abbreviated String
1165: * @return The abbreviated String.
1166: */
1167: public static String abbreviateDotSeparatedString(String string, int targetLength) {
1168:• if (string.length() <= targetLength) {
1169: return string;
1170: }
1171:
1172: String[] components = string.split(DOT_SEPARATOR_SPLIT_REGEX);
1173:
1174: int actualLength = string.length();
1175: StringBuilder builder = new StringBuilder();
1176: int index = 0;
1177:
1178:• while (actualLength > targetLength && index < components.length - 1) {
1179: String component = components[index++];
1180: builder.append(component.charAt(0));
1181: builder.append(DOT_SEPARATOR);
1182:
1183: actualLength -= (component.length() - 1);
1184: }
1185:
1186:• if (actualLength > targetLength) {
1187: return components[components.length - 1];
1188: } else {
1189:• for (int i = index; i < components.length; i++) {
1190: builder.append(components[i]);
1191:• if (i < components.length - 1) {
1192: builder.append(DOT_SEPARATOR);
1193: }
1194: }
1195: }
1196:
1197: return builder.toString();
1198: }
1199:
1200: }