001 package com.mockrunner.util.common; 002 003 import java.util.ArrayList; 004 import java.util.List; 005 006 import org.apache.commons.logging.Log; 007 import org.apache.commons.logging.LogFactory; 008 import org.apache.oro.text.regex.MalformedPatternException; 009 import org.apache.oro.text.regex.Pattern; 010 import org.apache.oro.text.regex.Perl5Compiler; 011 import org.apache.oro.text.regex.Perl5Matcher; 012 013 import com.mockrunner.base.NestedApplicationException; 014 015 /** 016 * Simple util class for <code>String</code> related methods. 017 */ 018 public class StringUtil 019 { 020 private final static Log log = LogFactory.getLog(StringUtil.class); 021 022 /** 023 * Compares two strings and returns the last 024 * index where the two string are equal. If 025 * the first characters of the two string do 026 * not match or if at least one of the two strings 027 * is empty, -1 is returned. 028 * @param string1 the first string 029 * @param string2 the second string 030 * @return the last index where the strings are equal 031 */ 032 public static int compare(String string1, String string2) 033 { 034 int endIndex = Math.min(string1.length(), string2.length()); 035 for(int ii = 0; ii < endIndex; ii++) 036 { 037 if(string1.charAt(ii) != string2.charAt(ii)) return ii - 1; 038 } 039 return endIndex - 1; 040 } 041 042 /** 043 * Converts the character at the specified index to 044 * lowercase and returns the resulting string. 045 * @param string the string to convert 046 * @param index the index where the character is set to lowercase 047 * @return the converted string 048 * @throws IndexOutOfBoundsException if the index is out of 049 * range 050 */ 051 public static String lowerCase(String string, int index) 052 { 053 return lowerCase(string, index, -1); 054 } 055 056 /** 057 * Converts the character in the specified index range to 058 * lowercase and returns the resulting string. 059 * If the provided endIndex is smaller or equal to startIndex, 060 * the endIndex is set to startIndex + 1. 061 * @param string the string to convert 062 * @param startIndex the index to start, inclusive 063 * @param endIndex the index to end, exclusive 064 * @return the converted string 065 * @throws IndexOutOfBoundsException if the index is out of 066 * range 067 */ 068 public static String lowerCase(String string, int startIndex, int endIndex) 069 { 070 StringBuffer buffer = new StringBuffer(string); 071 if(endIndex <= startIndex) endIndex = startIndex + 1; 072 for(int ii = startIndex; ii < endIndex; ii++) 073 { 074 char character = buffer.charAt(ii); 075 buffer.setCharAt(ii, Character.toLowerCase(character)); 076 } 077 return buffer.toString(); 078 } 079 080 /** 081 * Appends the entries in the specified <code>List</code> as strings 082 * with a terminating <i>"\n"</i> after each row. 083 * @param buffer the buffer 084 * @param data the <code>List</code> with the data 085 */ 086 public static void appendObjectsAsString(StringBuffer buffer, List data) 087 { 088 for(int ii = 0; ii < data.size(); ii++) 089 { 090 buffer.append(data.get(ii)); 091 buffer.append("\n"); 092 } 093 } 094 095 /** 096 * Appends <i>number</i> tabs (\t) to the buffer. 097 * @param buffer the buffer 098 * @param number the number of tabs to append 099 */ 100 public static void appendTabs(StringBuffer buffer, int number) 101 { 102 for(int ii = 0; ii < number; ii++) 103 { 104 buffer.append("\t"); 105 } 106 } 107 108 /** 109 * Splits a string into tokens. Similar to <code>StringTokenizer</code> 110 * except that empty tokens are recognized and added as <code>null</code>. 111 * With a delimiter of <i>";"</i> the string 112 * <i>"a;;b;c;;"</i> will split into 113 * <i>["a"] [null] ["b"] ["c"] [null]</i>. 114 * @param string the String 115 * @param delim the delimiter 116 * @param doTrim should each token be trimmed 117 * @return the array of tokens 118 */ 119 public static String[] split(String string, String delim, boolean doTrim) 120 { 121 int pos = 0, begin = 0; 122 ArrayList resultList = new ArrayList(); 123 while((-1 != (pos = string.indexOf(delim, begin))) && (begin < string.length())) 124 { 125 String token = string.substring(begin, pos); 126 if(doTrim) token = token.trim(); 127 if(token.length() == 0) token = null; 128 resultList.add(token); 129 begin = pos + delim.length(); 130 } 131 if(begin < string.length()) 132 { 133 String token = string.substring(begin); 134 if(doTrim) token = token.trim(); 135 if(token.length() == 0) token = null; 136 resultList.add(token); 137 } 138 return (String[])resultList.toArray(new String[resultList.size()]); 139 } 140 141 /** 142 * Returns how many times <code>string</code> contains 143 * <code>other</coder>. 144 * @param string the string to search 145 * @param other the string that is searched 146 * @return the number of occurences 147 */ 148 public static int countMatches(String string, String other) 149 { 150 if(null == string) return 0; 151 if(null == other) return 0; 152 if(0 >= string.length()) return 0; 153 if(0 >= other.length()) return 0; 154 int count = 0; 155 int index = 0; 156 while((index <= string.length() - other.length()) && (-1 != (index = string.indexOf(other, index)))) 157 { 158 count++; 159 index += other.length(); 160 } 161 return count; 162 } 163 164 165 /** 166 * Returns if the specified strings are equal, ignoring 167 * case, if <code>caseSensitive</code> is <code>false</code>. 168 * @param source the source String 169 * @param target the target String 170 * @param caseSensitive is the comparison case sensitive 171 * @return <code>true</code> if the strings matches 172 * <code>false</code> otherwise 173 */ 174 public static boolean matchesExact(String source, String target, boolean caseSensitive) 175 { 176 if(!caseSensitive) 177 { 178 source = source.toLowerCase(); 179 target = target.toLowerCase(); 180 } 181 return (source.equals(target)); 182 } 183 184 /** 185 * Returns if <code>source</code> contains <code>target</code>, 186 * ignoring case, if <code>caseSensitive</code> is <code>false</code>. 187 * @param source the source String 188 * @param target the target String 189 * @param caseSensitive is the comparison case sensitive 190 * @return <code>true</code> if the strings matches 191 * <code>false</code> otherwise 192 */ 193 public static boolean matchesContains(String source, String target, boolean caseSensitive) 194 { 195 if(!caseSensitive) 196 { 197 source = source.toLowerCase(); 198 target = target.toLowerCase(); 199 } 200 return (-1 != source.indexOf(target)); 201 } 202 203 /** 204 * Returns if the regular expression <code>target</code> matches 205 * <code>source</code>, ignoring case, if <code>caseSensitive</code> 206 * is <code>false</code>. 207 * @param source the source String 208 * @param target the target String 209 * @param caseSensitive is the comparison case sensitive 210 * @return <code>true</code> if the strings matches 211 * <code>false</code> otherwise 212 */ 213 public static boolean matchesPerl5(String source, String target, boolean caseSensitive) 214 { 215 int mask = Perl5Compiler.CASE_INSENSITIVE_MASK; 216 if(caseSensitive) 217 { 218 mask = Perl5Compiler.DEFAULT_MASK; 219 } 220 try 221 { 222 Pattern pattern = new Perl5Compiler().compile(target, mask); 223 return (new Perl5Matcher().matches(source, pattern)); 224 } 225 catch(MalformedPatternException exc) 226 { 227 log.error("Malformed pattern", exc); 228 throw new NestedApplicationException(exc); 229 } 230 } 231 }