View Javadoc

    1   /***
    2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
    3    */
    4   package net.sourceforge.pmd.util;
    5
    6   import java.util.ArrayList;
    7   import java.util.Iterator;
    8   import java.util.List;
    9
    10  public class StringUtil {
    11
    12  	public static final String[] EMPTY_STRINGS = new String[0];
    13      private static final boolean supportsUTF8 = System.getProperty("net.sourceforge.pmd.supportUTF8", "no").equals("yes");
    14      private static final String[] ENTITIES;
    15
    16      static {
    17          ENTITIES = new String[256 - 126];
    18          for (int i = 126; i <= 255; i++) {
    19              ENTITIES[i - 126] = "&#" + i + ';';
    20          }
    21      }
    22
    23      public static String replaceString(String original, char oldChar, String newString) {
    24
    25      	String fixedNew = newString == null ? "" : newString;
    26
    27          StringBuffer desc = new StringBuffer();
    28          int index = original.indexOf(oldChar);
    29          int last = 0;
    30          while (index != -1) {
    31              desc.append(original.substring(last, index));
    32              desc.append(fixedNew);
    33              last = index + 1;
    34              index = original.indexOf(oldChar, last);
    35          }
    36          desc.append(original.substring(last));
    37          return desc.toString();
    38      }
    39
    40      public static String replaceString(String original, String oldString, String newString) {
    41
    42      	String fixedNew = newString == null ? "" : newString;
    43
    44          StringBuffer desc = new StringBuffer();
    45          int index = original.indexOf(oldString);
    46          int last = 0;
    47          while (index != -1) {
    48              desc.append(original.substring(last, index));
    49              desc.append(fixedNew);
    50              last = index + oldString.length();
    51              index = original.indexOf(oldString, last);
    52          }
    53          desc.append(original.substring(last));
    54          return desc.toString();
    55      }
    56
    57      /***
    58       * Appends to a StringBuffer the String src where non-ASCII and
    59       * XML special chars are escaped.
    60       *
    61       * @param buf The destination XML stream
    62       * @param src The String to append to the stream
    63       */
    64      public static void appendXmlEscaped(StringBuffer buf, String src) {
    65          appendXmlEscaped(buf, src, supportsUTF8);
    66      }
    67
    68      public static String htmlEncode(String string) {
    69          String encoded = StringUtil.replaceString(string, '&', "&amp;");
    70          encoded = StringUtil.replaceString(encoded, '<', "&lt;");
    71          return StringUtil.replaceString(encoded, '>', "&gt;");
    72      }
    73
    74      // TODO - unify the method above with the one below
    75
    76      private static void appendXmlEscaped(StringBuffer buf, String src, boolean supportUTF8) {
    77          char c;
    78          for (int i = 0; i < src.length(); i++) {
    79              c = src.charAt(i);
    80              if (c > '~') {// 126
    81                  if (!supportUTF8) {
    82                      if (c <= 255) {
    83                          buf.append(ENTITIES[c - 126]);
    84                      } else {
    85                          buf.append("&u").append(Integer.toHexString(c)).append(';');
    86                      }
    87                  } else {
    88                      buf.append(c);
    89                  }
    90              } else if (c == '&')
    91                  buf.append("&amp;");
    92              else if (c == '"')
    93                  buf.append("&quot;");
    94              else if (c == '<')
    95                  buf.append("&lt;");
    96              else if (c == '>')
    97                  buf.append("&gt;");
    98              else
    99                  buf.append(c);
    100         }
    101     }
    102
    103 	/***
    104 	 * Parses the input source using the delimiter specified. This method is much
    105 	 * faster than using the StringTokenizer or String.split(char) approach and
    106 	 * serves as a replacement for String.split() for JDK1.3 that doesn't have it.
    107 	 *
    108 	 * @param source String
    109 	 * @param delimiter char
    110 	 * @return String[]
    111 	 */
    112 	public static String[] substringsOf(String source, char delimiter) {
    113
    114 		if (source == null || source.length() == 0) {
    115             return EMPTY_STRINGS;
    116         }
    117
    118 		int delimiterCount = 0;
    119 		int length = source.length();
    120 		char[] chars = source.toCharArray();
    121
    122 		for (int i=0; i<length; i++) {
    123 			if (chars[i] == delimiter) delimiterCount++;
    124 			}
    125
    126 		if (delimiterCount == 0) return new String[] { source };
    127
    128 		String results[] = new String[delimiterCount+1];
    129
    130 		int i = 0;
    131 		int offset = 0;
    132
    133 		while (offset <= length) {
    134 			int pos = source.indexOf(delimiter, offset);
    135 			if (pos < 0) pos = length;
    136 			results[i++] = pos == offset ? "" : source.substring(offset, pos);
    137 			offset = pos + 1;
    138 			}
    139
    140 		return results;
    141 	}
    142
    143 	/***
    144 	 * Much more efficient than StringTokenizer.
    145 	 *
    146 	 * @param str String
    147 	 * @param separator char
    148 	 * @return String[]
    149 	 */
    150 	  public static String[] substringsOf(String str, String separator) {
    151
    152 	        if (str == null || str.length() == 0) {
    153 	            return EMPTY_STRINGS;
    154 	        }
    155
    156 	        int index = str.indexOf(separator);
    157 	        if (index == -1) {
    158 	            return new String[]{str};
    159 	        }
    160
    161 	        List list = new ArrayList();
    162 	        int currPos = 0;
    163 	        int len = separator.length();
    164 	        while (index != -1) {
    165 	            list.add(str.substring(currPos, index));
    166 	            currPos = index + len;
    167 	            index = str.indexOf(separator, currPos);
    168 	        }
    169 	        list.add(str.substring(currPos));
    170 	        return (String[]) list.toArray(new String[list.size()]);
    171 	    }
    172
    173
    174 	/***
    175 	 * Copies the elements returned by the iterator onto the string buffer
    176 	 * each delimited by the separator.
    177 	 *
    178 	 * @param sb StringBuffer
    179 	 * @param iter Iterator
    180 	 * @param separator String
    181 	 */
    182 	public static void asStringOn(StringBuffer sb, Iterator iter, String separator) {
    183
    184 	    if (!iter.hasNext()) return;
    185
    186 	    sb.append(iter.next());
    187
    188 	    while (iter.hasNext()) {
    189 	    	sb.append(separator);
    190 	        sb.append(iter.next());
    191 	    }
    192 	}
    193 	/***
    194 	 * Return the length of the shortest string in the array.
    195 	 * If any one of them is null then it returns 0.
    196 	 *
    197 	 * @param strings String[]
    198 	 * @return int
    199 	 */
    200 	public static int lengthOfShortestIn(String[] strings) {
    201
    202 		int minLength = Integer.MAX_VALUE;
    203
    204 		for (int i=0; i<strings.length; i++) {
    205 			if (strings[i] == null) return 0;
    206 			minLength = Math.min(minLength, strings[i].length());
    207 		}
    208
    209 		return minLength;
    210 	}
    211
    212 	/***
    213 	 * Determine the maximum number of common leading whitespace characters
    214 	 * the strings share in the same sequence. Useful for determining how
    215 	 * many leading characters can be removed to shift all the text in the
    216 	 * strings to the left without misaligning them.
    217 	 *
    218 	 * @param strings String[]
    219 	 * @return int
    220 	 */
    221 	public static int maxCommonLeadingWhitespaceForAll(String[] strings) {
    222
    223 		int shortest = lengthOfShortestIn(strings);
    224 		if (shortest == 0) return 0;
    225
    226 		char[] matches = new char[shortest];
    227
    228 		String str;
    229 		for (int m=0; m<matches.length; m++) {
    230 			matches[m] = strings[0].charAt(m);
    231 			if (!Character.isWhitespace(matches[m])) return m;
    232 			for (int i=0; i<strings.length; i++) {
    233 				str = strings[i];
    234 				if (str.charAt(m) != matches[m])  return m;
    235 				}
    236 		}
    237
    238 		return shortest;
    239 	}
    240
    241 	/***
    242 	 * Trims off the leading characters off the strings up to the trimDepth
    243 	 * specified. Returns the same strings if trimDepth = 0
    244 	 *
    245 	 * @param strings
    246 	 * @param trimDepth
    247 	 * @return String[]
    248 	 */
    249 	public static String[] trimStartOn(String[] strings, int trimDepth) {
    250
    251 		if (trimDepth == 0) return strings;
    252
    253 		String[] results = new String[strings.length];
    254 		for (int i=0; i<strings.length; i++) {
    255 			results[i] = strings[i].substring(trimDepth);
    256 		}
    257 		return results;
    258 	}
    259 }