View Javadoc
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 &lt; 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 }