1 /* ==================================================================== 2 * The Apache Software License, Version 1.1 3 * 4 * Copyright (c) 2002 The Apache Software Foundation. All rights 5 * reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * 3. The end-user documentation included with the redistribution, if 20 * any, must include the following acknowledgement: 21 * "This product includes software developed by the 22 * Apache Software Foundation (http://www.codehaus.org/)." 23 * Alternately, this acknowledgement may appear in the software itself, 24 * if and wherever such third-party acknowledgements normally appear. 25 * 26 * 4. The names "The Jakarta Project", "Commons", and "Apache Software 27 * Foundation" must not be used to endorse or promote products derived 28 * from this software without prior written permission. For written 29 * permission, please contact codehaus@codehaus.org. 30 * 31 * 5. Products derived from this software may not be called "Apache" 32 * nor may "Apache" appear in their names without prior written 33 * permission of the Apache Software Foundation. 34 * 35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46 * SUCH DAMAGE. 47 * ==================================================================== 48 * 49 * This software consists of voluntary contributions made by many 50 * individuals on behalf of the Apache Software Foundation. For more 51 * information on the Apache Software Foundation, please see 52 * <http://www.codehaus.org/>. 53 */ 54 package org.codehaus.plexus.util.xml; 55 56 import java.util.StringTokenizer; 57 58 /** 59 * <p> 60 * Common <code>String</code> manipulation routines, extracted from Plexus Utils and trimmed down for Plexus Xml. 61 * </p> 62 * <p> 63 * Originally from <a href="http://jakarta.apache.org/turbine/">Turbine</a> and the GenerationJavaCore library. 64 * </p> 65 * 66 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> 67 * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> 68 * @author <a href="mailto:gcoladonato@yahoo.com">Greg Coladonato</a> 69 * @author <a href="mailto:bayard@generationjava.com">Henri Yandell</a> 70 * @author <a href="mailto:ed@codehaus.org">Ed Korthof</a> 71 * @author <a href="mailto:rand_mcneely@yahoo.com">Rand McNeely</a> 72 * @author Stephen Colebourne 73 * @author <a href="mailto:fredrik@westermarck.com">Fredrik Westermarck</a> 74 * @author Holger Krauth 75 * @author <a href="mailto:alex@purpletech.com">Alexander Day Chaffee</a> 76 * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a> 77 * @since 1.0 78 * 79 */ 80 class StringUtils { 81 /** 82 * <p> 83 * <code>StringUtils</code> instances should NOT be constructed in standard programming. Instead, the class should 84 * be used as <code>StringUtils.trim(" foo ");</code>. 85 * </p> 86 * <p> 87 * This constructor is public to permit tools that require a JavaBean manager to operate. 88 * </p> 89 */ 90 private StringUtils() {} 91 92 /** 93 * Checks if a String is <code>null</code> or empty. 94 * <p> 95 * <strong>Note:</strong> In releases prior 3.5.0, this method trimmed the input string such that it worked 96 * the same as {@link #isBlank(String)}. Since release 3.5.0 it no longer returns {@code true} for strings 97 * containing only whitespace characters. 98 * 99 * @param str the String to check 100 * @return <code>true</code> if the String is <code>null</code>, or length zero 101 */ 102 public static boolean isEmpty(String str) { 103 return ((str == null) || (str.isEmpty())); 104 } 105 106 // Splitting 107 // -------------------------------------------------------------------------- 108 109 /** 110 * @param text The string to parse. 111 * @param separator Characters used as the delimiters. If <code>null</code>, splits on whitespace. 112 * @return an array of parsed Strings 113 */ 114 public static String[] split(String text, String separator) { 115 return split(text, separator, -1); 116 } 117 118 /** 119 * <p> 120 * Splits the provided text into a array, based on a given separator. 121 * </p> 122 * <p> 123 * The separator is not included in the returned String array. The maximum number of splits to perform can be 124 * controlled. A <code>null</code> separator will cause parsing to be on whitespace. 125 * </p> 126 * <p> 127 * This is useful for quickly splitting a String directly into an array of tokens, instead of an enumeration of 128 * tokens (as <code>StringTokenizer</code> does). 129 * </p> 130 * 131 * @param str The string to parse. 132 * @param separator Characters used as the delimiters. If <code>null</code>, splits on whitespace. 133 * @param max The maximum number of elements to include in the array. A zero or negative value implies no limit. 134 * @return an array of parsed Strings 135 */ 136 private static String[] split(String str, String separator, int max) { 137 StringTokenizer tok; 138 if (separator == null) { 139 // Null separator means we're using StringTokenizer's default 140 // delimiter, which comprises all whitespace characters. 141 tok = new StringTokenizer(str); 142 } else { 143 tok = new StringTokenizer(str, separator); 144 } 145 146 int listSize = tok.countTokens(); 147 if ((max > 0) && (listSize > max)) { 148 listSize = max; 149 } 150 151 String[] list = new String[listSize]; 152 int i = 0; 153 int lastTokenBegin; 154 int lastTokenEnd = 0; 155 while (tok.hasMoreTokens()) { 156 if ((max > 0) && (i == listSize - 1)) { 157 // In the situation where we hit the max yet have 158 // tokens left over in our input, the last list 159 // element gets all remaining text. 160 String endToken = tok.nextToken(); 161 lastTokenBegin = str.indexOf(endToken, lastTokenEnd); 162 list[i] = str.substring(lastTokenBegin); 163 break; 164 } else { 165 list[i] = tok.nextToken(); 166 lastTokenBegin = str.indexOf(list[i], lastTokenEnd); 167 lastTokenEnd = lastTokenBegin + list[i].length(); 168 } 169 i++; 170 } 171 return list; 172 } 173 174 /** 175 * <p> 176 * Repeat a String <code>n</code> times to form a new string. 177 * </p> 178 * 179 * @param str String to repeat 180 * @param repeat number of times to repeat str 181 * @return String with repeated String 182 * @throws NegativeArraySizeException if <code>repeat < 0</code> 183 * @throws NullPointerException if str is <code>null</code> 184 */ 185 public static String repeat(String str, int repeat) { 186 StringBuilder buffer = new StringBuilder(repeat * str.length()); 187 for (int i = 0; i < repeat; i++) { 188 buffer.append(str); 189 } 190 return buffer.toString(); 191 } 192 193 /** 194 * Remove all duplicate whitespace characters and line terminators are replaced with a single space. 195 * 196 * @param s a not null String 197 * @return a string with unique whitespace. 198 * @since 1.5.7 199 */ 200 public static String removeDuplicateWhitespace(String s) { 201 StringBuilder result = new StringBuilder(); 202 int length = s.length(); 203 boolean isPreviousWhiteSpace = false; 204 for (int i = 0; i < length; i++) { 205 char c = s.charAt(i); 206 boolean thisCharWhiteSpace = Character.isWhitespace(c); 207 if (!(isPreviousWhiteSpace && thisCharWhiteSpace)) { 208 result.append(c); 209 } 210 isPreviousWhiteSpace = thisCharWhiteSpace; 211 } 212 return result.toString(); 213 } 214 215 /** 216 * Parses the given String and replaces all occurrences of '\n', '\r' and '\r\n' with the system line separator. 217 * 218 * @param s a not null String 219 * @param ls the wanted line separator ("\n" on UNIX), if null using the System line separator. 220 * @return a String that contains only System line separators. 221 * @throws IllegalArgumentException if ls is not '\n', '\r' and '\r\n' characters. 222 * @since 1.5.7 223 */ 224 public static String unifyLineSeparators(String s, String ls) { 225 if (s == null) { 226 return null; 227 } 228 229 if (ls == null) { 230 ls = System.getProperty("line.separator"); 231 } 232 233 if (!(ls.equals("\n") || ls.equals("\r") || ls.equals("\r\n"))) { 234 throw new IllegalArgumentException("Requested line separator is invalid."); 235 } 236 237 int length = s.length(); 238 239 StringBuilder buffer = new StringBuilder(length); 240 for (int i = 0; i < length; i++) { 241 if (s.charAt(i) == '\r') { 242 if ((i + 1) < length && s.charAt(i + 1) == '\n') { 243 i++; 244 } 245 246 buffer.append(ls); 247 } else if (s.charAt(i) == '\n') { 248 buffer.append(ls); 249 } else { 250 buffer.append(s.charAt(i)); 251 } 252 } 253 254 return buffer.toString(); 255 } 256 }