001: package com.mockrunner.util.common;
002:
003: import java.lang.reflect.Array;
004: import java.util.ArrayList;
005: import java.util.Collection;
006: import java.util.Iterator;
007: import java.util.List;
008: import java.util.Map;
009:
010: import org.apache.oro.text.regex.MalformedPatternException;
011: import org.apache.oro.text.regex.Pattern;
012: import org.apache.oro.text.regex.Perl5Compiler;
013: import org.apache.oro.text.regex.Perl5Matcher;
014:
015: import com.mockrunner.base.NestedApplicationException;
016:
017: /**
018: * Simple util class for <code>String</code> related methods.
019: */
020: public class StringUtil {
021: /**
022: * Replaces all occurrences of <code>match</code> in
023: * <code>source</code> with <code>replacement</code>.
024: * @param source the source string
025: * @param match the string that is searched
026: * @param replacement the replacement string
027: * @return the modified string
028: * @throws IllegalArgumentException if any argument is <code>null</code> or
029: * if <code>match</code> is the empty string
030: */
031: public static String replaceAll(String source, String match,
032: String replacement) {
033: if (null == source || null == match || null == replacement) {
034: throw new IllegalArgumentException(
035: "null strings not allowed");
036: }
037: if (match.length() <= 0) {
038: throw new IllegalArgumentException(
039: "match must not be empty");
040: }
041: StringBuffer buffer = new StringBuffer(source.length() + 10);
042: int index = 0;
043: int newIndex = 0;
044: while ((newIndex = source.indexOf(match, index)) >= 0) {
045: buffer.append(source.substring(index, newIndex));
046: buffer.append(replacement);
047: index = newIndex + match.length();
048: }
049: buffer.append(source.substring(index));
050: return buffer.toString();
051: }
052:
053: /**
054: * Compares two strings and returns the last
055: * index where the two string are equal. If
056: * the first characters of the two string do
057: * not match or if at least one of the two strings
058: * is empty, -1 is returned.
059: * @param string1 the first string
060: * @param string2 the second string
061: * @return the last index where the strings are equal
062: */
063: public static int compare(String string1, String string2) {
064: int endIndex = Math.min(string1.length(), string2.length());
065: for (int ii = 0; ii < endIndex; ii++) {
066: if (string1.charAt(ii) != string2.charAt(ii))
067: return ii - 1;
068: }
069: return endIndex - 1;
070: }
071:
072: /**
073: * Converts the character at the specified index to
074: * lowercase and returns the resulting string.
075: * @param string the string to convert
076: * @param index the index where the character is set to lowercase
077: * @return the converted string
078: * @throws IndexOutOfBoundsException if the index is out of
079: * range
080: */
081: public static String lowerCase(String string, int index) {
082: return lowerCase(string, index, -1);
083: }
084:
085: /**
086: * Converts the character in the specified index range to
087: * lowercase and returns the resulting string.
088: * If the provided endIndex is smaller or equal to startIndex,
089: * the endIndex is set to startIndex + 1.
090: * @param string the string to convert
091: * @param startIndex the index to start, inclusive
092: * @param endIndex the index to end, exclusive
093: * @return the converted string
094: * @throws IndexOutOfBoundsException if the index is out of
095: * range
096: */
097: public static String lowerCase(String string, int startIndex,
098: int endIndex) {
099: StringBuffer buffer = new StringBuffer(string);
100: if (endIndex <= startIndex)
101: endIndex = startIndex + 1;
102: for (int ii = startIndex; ii < endIndex; ii++) {
103: char character = buffer.charAt(ii);
104: buffer.setCharAt(ii, Character.toLowerCase(character));
105: }
106: return buffer.toString();
107: }
108:
109: /**
110: * Helper method for <code>toString()</code> implementations.
111: * Returns a string <code>"field name: value"</code>. Handles
112: * <code>null</code> values, collections and arrays. If the
113: * field is a collection or an array, the returned string will
114: * be:<br>
115: * <code>"field name 0: value0\nfield name 1: value1"</code>
116: * @param fieldName the field name
117: * @param field the field value
118: * @return a suitable string for <code>toString()</code> implementations
119: */
120: public static String fieldToString(String fieldName, Object field) {
121: StringBuffer buffer = new StringBuffer();
122: if (null == field) {
123: buffer.append(fieldName + ": " + "null");
124: } else if (field.getClass().isArray()) {
125: arrayToString(fieldName, field, buffer);
126: } else if (field instanceof Collection) {
127: collectionToString(fieldName, field, buffer);
128: } else if (field instanceof Map) {
129: mapToString(fieldName, field, buffer);
130: } else {
131: buffer.append(fieldName + ": " + field.toString());
132: }
133: return buffer.toString();
134: }
135:
136: private static void arrayToString(String fieldName, Object field,
137: StringBuffer buffer) {
138: int length = Array.getLength(field);
139: if (0 >= length) {
140: buffer.append(fieldName + ": " + "empty");
141: } else {
142: for (int ii = 0; ii < length; ii++) {
143: buffer.append(fieldToString(fieldName + " " + ii, Array
144: .get(field, ii)));
145: if (ii < length - 1) {
146: buffer.append("\n");
147: }
148: }
149: }
150: }
151:
152: private static void collectionToString(String fieldName,
153: Object field, StringBuffer buffer) {
154: List list = new ArrayList((Collection) field);
155: if (0 >= list.size()) {
156: buffer.append(fieldName + ": " + "empty");
157: } else {
158: for (int ii = 0; ii < list.size(); ii++) {
159: buffer.append(fieldToString(fieldName + " " + ii, list
160: .get(ii)));
161: if (ii < list.size() - 1) {
162: buffer.append("\n");
163: }
164: }
165: }
166: }
167:
168: private static void mapToString(String fieldName, Object field,
169: StringBuffer buffer) {
170: if (0 >= ((Map) field).size()) {
171: buffer.append(fieldName + ": " + "empty");
172: } else {
173: Iterator keys = ((Map) field).keySet().iterator();
174: int ii = 0;
175: while (keys.hasNext()) {
176: Object key = keys.next();
177: Object value = ((Map) field).get(key);
178: buffer.append(fieldToString(fieldName + " " + key,
179: value));
180: if (ii < ((Map) field).size() - 1) {
181: buffer.append("\n");
182: }
183: ii++;
184: }
185: }
186: }
187:
188: /**
189: * Appends the entries in the specified <code>List</code> as strings
190: * with a terminating <i>"\n"</i> after each row.
191: * @param buffer the buffer
192: * @param data the <code>List</code> with the data
193: */
194: public static void appendObjectsAsString(StringBuffer buffer,
195: List data) {
196: for (int ii = 0; ii < data.size(); ii++) {
197: buffer.append(data.get(ii));
198: buffer.append("\n");
199: }
200: }
201:
202: /**
203: * Appends <i>number</i> tabs (\t) to the buffer.
204: * @param buffer the buffer
205: * @param number the number of tabs to append
206: */
207: public static void appendTabs(StringBuffer buffer, int number) {
208: for (int ii = 0; ii < number; ii++) {
209: buffer.append("\t");
210: }
211: }
212:
213: /**
214: * Splits a string into tokens. Similar to <code>StringTokenizer</code>
215: * except that empty tokens are recognized and added as <code>null</code>.
216: * With a delimiter of <i>";"</i> the string
217: * <i>"a;;b;c;;"</i> will split into
218: * <i>["a"] [null] ["b"] ["c"] [null]</i>.
219: * @param string the String
220: * @param delim the delimiter
221: * @param doTrim should each token be trimmed
222: * @return the array of tokens
223: */
224: public static String[] split(String string, String delim,
225: boolean doTrim) {
226: int pos = 0, begin = 0;
227: ArrayList resultList = new ArrayList();
228: while ((-1 != (pos = string.indexOf(delim, begin)))
229: && (begin < string.length())) {
230: String token = string.substring(begin, pos);
231: if (doTrim)
232: token = token.trim();
233: if (token.length() == 0)
234: token = null;
235: resultList.add(token);
236: begin = pos + delim.length();
237: }
238: if (begin < string.length()) {
239: String token = string.substring(begin);
240: if (doTrim)
241: token = token.trim();
242: if (token.length() == 0)
243: token = null;
244: resultList.add(token);
245: }
246: return (String[]) resultList.toArray(new String[resultList
247: .size()]);
248: }
249:
250: /**
251: * Returns how many times <code>string</code> contains
252: * <code>other</code>.
253: * @param string the string to search
254: * @param other the string that is searched
255: * @return the number of occurences
256: */
257: public static int countMatches(String string, String other) {
258: if (null == string)
259: return 0;
260: if (null == other)
261: return 0;
262: if (0 >= string.length())
263: return 0;
264: if (0 >= other.length())
265: return 0;
266: int count = 0;
267: int index = 0;
268: while ((index <= string.length() - other.length())
269: && (-1 != (index = string.indexOf(other, index)))) {
270: count++;
271: index += other.length();
272: }
273: return count;
274: }
275:
276: /**
277: * Returns if the specified strings are equal, ignoring
278: * case, if <code>caseSensitive</code> is <code>false</code>.
279: * @param source the source String
280: * @param target the target String
281: * @param caseSensitive is the comparison case sensitive
282: * @return <code>true</code> if the strings matches
283: * <code>false</code> otherwise
284: */
285: public static boolean matchesExact(String source, String target,
286: boolean caseSensitive) {
287: if (!caseSensitive) {
288: source = source.toLowerCase();
289: target = target.toLowerCase();
290: }
291: return (source.equals(target));
292: }
293:
294: /**
295: * Returns if <code>source</code> contains <code>target</code>,
296: * ignoring case, if <code>caseSensitive</code> is <code>false</code>.
297: * @param source the source String
298: * @param target the target String
299: * @param caseSensitive is the comparison case sensitive
300: * @return <code>true</code> if the strings matches
301: * <code>false</code> otherwise
302: */
303: public static boolean matchesContains(String source, String target,
304: boolean caseSensitive) {
305: if (!caseSensitive) {
306: source = source.toLowerCase();
307: target = target.toLowerCase();
308: }
309: return (-1 != source.indexOf(target));
310: }
311:
312: /**
313: * Returns if the regular expression <code>target</code> matches
314: * <code>source</code>, ignoring case, if <code>caseSensitive</code>
315: * is <code>false</code>.
316: * @param source the source String
317: * @param target the target String
318: * @param caseSensitive is the comparison case sensitive
319: * @return <code>true</code> if the strings matches
320: * <code>false</code> otherwise
321: */
322: public static boolean matchesPerl5(String source, String target,
323: boolean caseSensitive) {
324: int mask = Perl5Compiler.CASE_INSENSITIVE_MASK;
325: if (caseSensitive) {
326: mask = Perl5Compiler.DEFAULT_MASK;
327: }
328: try {
329: Pattern pattern = new Perl5Compiler().compile(target, mask);
330: return (new Perl5Matcher().matches(source, pattern));
331: } catch (MalformedPatternException exc) {
332: throw new NestedApplicationException(exc);
333: }
334: }
335: }
|