| package org.apache.commons.lang; |
| |
| /* ==================================================================== |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 2002 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, if |
| * any, must include the following acknowlegement: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowlegement may appear in the software itself, |
| * if and wherever such third-party acknowlegements normally appear. |
| * |
| * 4. The names "The Jakarta Project", "Commons", and "Apache Software |
| * Foundation" must not be used to endorse or promote products derived |
| * from this software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache" |
| * nor may "Apache" appear in their names without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| import java.util.StringTokenizer; |
| |
| import java.util.Iterator; |
| |
| /** |
| * <p>Common <code>String</code> manipulation routines.</p> |
| * |
| * <p>Originally from |
| * <a href="http://jakarta.apache.org/turbine/">Turbine</a> and the |
| * GenerationJavaCore library.</p> |
| * |
| * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> |
| * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> |
| * @author <a href="mailto:gcoladonato@yahoo.com">Greg Coladonato</a> |
| * @author <a href="mailto:bayard@generationjava.com">Henri Yandell</a> |
| * @author <a href="mailto:ed@apache.org">Ed Korthof</a> |
| * @author <a href="mailto:rand_mcneely@yahoo.com>Rand McNeely</a> |
| * @author <a href="mailto:scolebourne@joda.org>Stephen Colebourne</a> |
| * @author <a href="mailto:fredrik@westermarck.com>Fredrik Westermarck</a> |
| * @version $Id: StringUtils.java,v 1.15 2002/09/27 06:08:16 bayard Exp $ |
| */ |
| public class StringUtils { |
| |
| /** |
| * The size of the buffer to use when working with I/O (4 kB). |
| */ |
| public static final int CHAR_BUFFER_SIZE = 4 * 1024; |
| |
| /** |
| * StringUtils instances should NOT be constructed in standard programming. |
| * Instead, the class should be used as <code>StringUtils.trim(" foo ");</code>. |
| * This constructor is public to permit tools that require a JavaBean instance |
| * to operate. |
| */ |
| public StringUtils() { |
| } |
| |
| // Empty |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Removes control characters, including whitespace, from both ends of this |
| * string, handling null by returning an empty string. |
| * |
| * @see java.lang.String#trim() |
| * @param str the string to check |
| * @return the trimmed text (never <code>null</code>) |
| */ |
| public static String clean(String str) { |
| return (str == null ? "" : str.trim()); |
| } |
| |
| /** |
| * Removes control characters, including whitespace, from both ends of this |
| * string, handling null by returning null. |
| * |
| * @see java.lang.String#trim() |
| * @param str the string to check |
| * @return the trimmed text (or <code>null</code>) |
| */ |
| public static String trim(String str) { |
| return (str == null ? null : str.trim()); |
| } |
| |
| /** |
| * Deletes all 'space' characters from a String. |
| * Spaces are defined as {' ', '\t', '\r', '\n', '\b'} |
| * in line with the deprecated Character.isSpace |
| * |
| * @param str String target to delete spaces from |
| * @return the text without spaces |
| * @throws NullPointerException |
| */ |
| public static String deleteSpaces(String str) { |
| return CharSetUtils.delete(str, " \t\r\n\b"); |
| } |
| |
| /** |
| * Deletes all whitespace from a String. |
| * Whitespace is defined by Character.isWhitespace |
| * |
| * @param str String target to delete whitespace from |
| * @return the text without whitespace |
| * @throws NullPointerException |
| */ |
| public static String deleteWhitespace(String str) { |
| StringBuffer buffer = new StringBuffer(); |
| int sz = str.length(); |
| for (int i=0; i<sz; i++) { |
| if(!Character.isWhitespace(str.charAt(i))) { |
| buffer.append(str.charAt(i)); |
| } |
| } |
| return buffer.toString(); |
| } |
| |
| /** |
| * Checks if a String is non null and is not empty (length > 0). |
| * |
| * @param str the string to check |
| * @return true if the String is non-null, and not length zero |
| */ |
| public static boolean isNotEmpty(String str) { |
| return (str != null && str.length() > 0); |
| } |
| |
| /** |
| * Checks if a (trimmed) String is null or empty. |
| * |
| * @param str the string to check |
| * @return true if the String is null, or length zero once trimmed |
| */ |
| public static boolean isEmpty(String str) { |
| return (str == null || str.trim().length() == 0); |
| } |
| |
| // Equals and IndexOf |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Compares two Strings, returning true if they are equal. |
| * Nulls are handled without exceptions. Two <code>null</code> |
| * references are considered equal. Comparison is case sensitive. |
| * |
| * @see java.lang.String#equals(String) |
| * @param str1 the first string |
| * @param str2 the second string |
| * @return true if the Strings are equal, case sensitive, or both null |
| */ |
| public static boolean equals(String str1, String str2) { |
| return (str1 == null ? str2 == null : str1.equals(str2)); |
| } |
| |
| /** |
| * Compares two Strings, returning true if they are equal ignoring case. |
| * Nulls are handled without exceptions. Two <code>null</code> |
| * references are considered equal. Comparison is case insensitive. |
| * @see java.lang.String#equalsIgnoreCase(String) |
| * @param str1 the first string |
| * @param str2 the second string |
| * @return true if the Strings are equal, case insensitive, or both null |
| */ |
| public static boolean equalsIgnoreCase(String str1, String str2) { |
| return (str1 == null ? str2 == null : str1.equalsIgnoreCase(str2)); |
| } |
| |
| /** |
| * Find the earliest index of any of a set of potential substrings. |
| * Null string will return -1. |
| * |
| * @param str the string to check |
| * @param searchStrs the strings to search for |
| * @return the earliest index of any of the strings |
| * @throws NullPointerException if any of searchStrs[i] is null |
| */ |
| public static int indexOfAny(String str, String[] searchStrs) { |
| if ((str == null) || (searchStrs == null)) { |
| return -1; |
| } |
| int sz = searchStrs.length; |
| |
| // String's can't have a MAX_VALUEth index. |
| int ret = Integer.MAX_VALUE; |
| |
| int tmp = 0; |
| for (int i = 0; i < sz; i++) { |
| tmp = str.indexOf(searchStrs[i]); |
| if (tmp == -1) { |
| continue; |
| } |
| |
| if (tmp < ret) { |
| ret = tmp; |
| } |
| } |
| |
| return (ret == Integer.MAX_VALUE) ? -1 : ret; |
| } |
| |
| /** |
| * Find the latest index of any of a set of potential substrings. |
| * Null string will return -1. |
| * |
| * @param str the string to check |
| * @param searchStrs the strings to search for |
| * @return the last index of any of the strings |
| * @throws NullPointerException if any of searchStrs[i] is null |
| */ |
| public static int lastIndexOfAny(String str, String[] searchStrs) { |
| if ((str == null) || (searchStrs == null)) { |
| return -1; |
| } |
| int sz = searchStrs.length; |
| int ret = -1; |
| int tmp = 0; |
| for (int i = 0; i < sz; i++) { |
| tmp = str.lastIndexOf(searchStrs[i]); |
| if (tmp > ret) { |
| ret = tmp; |
| } |
| } |
| return ret; |
| } |
| |
| // Substring |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Gets a substring of the specified string avoiding exceptions. |
| * A negative start position can be used to start n characters from |
| * the end of the string. |
| * |
| * @param str the string to get the substring from |
| * @param start the position to start from, negative means |
| * count back from the end of the string by this many characters |
| * @return substring from start position |
| */ |
| public static String substring(String str, int start) { |
| if (str == null) { |
| return null; |
| } |
| |
| // handle negatives, which means last n characters |
| if (start < 0) { |
| start = str.length() + start; // remember start is negative |
| } |
| |
| if (start < 0) { |
| start = 0; |
| } |
| if (start > str.length()) { |
| return ""; |
| } |
| |
| return str.substring(start); |
| } |
| |
| /** |
| * Gets a substring of the specified string avoiding exceptions. |
| * A negative start position can be used to start/end n characters |
| * from the end of the string. |
| * |
| * @param str the string to get the substring from |
| * @param start the position to start from, negative means |
| * count back from the end of the string by this many characters |
| * @param end the position to end at (exclusive), negative means |
| * count back from the end of the string by this many characters |
| * @return substring from start position to end positon |
| */ |
| public static String substring(String str, int start, int end) { |
| if (str == null) { |
| return null; |
| } |
| |
| // handle negatives |
| if (end < 0) { |
| end = str.length() + end; // remember end is negative |
| } |
| if (start < 0) { |
| start = str.length() + start; // remember start is negative |
| } |
| |
| // check length next |
| if (end > str.length()) { |
| // check this works. |
| end = str.length(); |
| } |
| |
| // if start is greater than end, return "" |
| if (start > end) { |
| return ""; |
| } |
| |
| if (start < 0) { |
| start = 0; |
| } |
| if (end < 0) { |
| end = 0; |
| } |
| |
| return str.substring(start, end); |
| } |
| |
| /** |
| * Gets the leftmost n characters of a string. If n characters are not |
| * available, or the string is null, the string will be returned |
| * without an exception. |
| * |
| * @param str the string to get the leftmost characters from |
| * @param len the length of the required string |
| * @return the leftmost characters |
| * @throws IllegalArgumentException if len is less than zero |
| */ |
| public static String left(String str, int len) { |
| if (len < 0) { |
| throw new IllegalArgumentException("Requested String length " + len + " is less than zero"); |
| } |
| if ((str == null) || (str.length() <= len)) { |
| return str; |
| } else { |
| return str.substring(0, len); |
| } |
| } |
| |
| /** |
| * Gets the rightmost n characters of a string. If n characters are not |
| * available, or the string is null, the string will be returned |
| * without an exception. |
| * |
| * @param str the string to get the rightmost characters from |
| * @param len the length of the required string |
| * @return the leftmost characters |
| * @throws IllegalArgumentException if len is less than zero |
| */ |
| public static String right(String str, int len) { |
| if (len < 0) { |
| throw new IllegalArgumentException("Requested String length " + len + " is less than zero"); |
| } |
| if ((str == null) || (str.length() <= len)) { |
| return str; |
| } else { |
| return str.substring(str.length() - len); |
| } |
| } |
| |
| /** |
| * Gets n characters from the middle of a string. If n characters are |
| * not available, the remainder of the string will be returned |
| * without an exception. If the string is null, null will be returned. |
| * |
| * @param str the string to get the characters from |
| * @param pos the position to start from |
| * @param len the length of the required string |
| * @return the leftmost characters |
| * @throws IndexOutOfBoundsException if pos is out of bounds |
| * @throws IllegalArgumentException if len is less than zero |
| */ |
| public static String mid(String str, int pos, int len) { |
| if ((pos < 0) || |
| (str != null && pos > str.length())) { |
| throw new StringIndexOutOfBoundsException("String index " + pos + " is out of bounds"); |
| } |
| if (len < 0) { |
| throw new IllegalArgumentException("Requested String length " + len + " is less than zero"); |
| } |
| if (str == null) { |
| return null; |
| } |
| if (str.length() <= (pos + len)) { |
| return str.substring(pos); |
| } else { |
| return str.substring(pos, pos + len); |
| } |
| } |
| |
| // Splitting |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Splits the provided text into a list, using whitespace as the separator. |
| * The separator is not included in the returned String array. |
| * |
| * @param str the string to parse |
| * @return an array of parsed Strings |
| */ |
| public static String[] split(String str) { |
| return split(str, null, -1); |
| } |
| |
| /** |
| * @see #split(String, String, int) |
| */ |
| public static String[] split(String text, String separator) { |
| return split(text, separator, -1); |
| } |
| |
| /** |
| * Splits the provided text into a list, based on a given separator. |
| * The separator is not included in the returned String array. |
| * The maximum number of splits to perfom can be controlled. |
| * A null separator will cause parsing to be on whitespace. |
| * |
| * <p>This is useful for quickly splitting a string directly into |
| * an array of tokens, instead of an enumeration of tokens (as |
| * <code>StringTokenizer</code> does). |
| * |
| * @param str The string to parse. |
| * @param separator Characters used as the delimiters. If |
| * <code>null</code>, splits on whitespace. |
| * @param max The maximum number of elements to include in the |
| * list. A zero or negative value implies no limit. |
| * @return an array of parsed Strings |
| */ |
| public static String[] split(String str, String separator, int max) { |
| StringTokenizer tok = null; |
| if (separator == null) { |
| // Null separator means we're using StringTokenizer's default |
| // delimiter, which comprises all whitespace characters. |
| tok = new StringTokenizer(str); |
| } else { |
| tok = new StringTokenizer(str, separator); |
| } |
| |
| int listSize = tok.countTokens(); |
| if (max > 0 && listSize > max) { |
| listSize = max; |
| } |
| |
| String[] list = new String[listSize]; |
| int i = 0; |
| while (tok.hasMoreTokens()) { |
| if (max > 0 && i == listSize - 1) { |
| // In the situation where we hit the max yet have |
| // tokens left over in our input, the last list |
| // element gets all remaining text. |
| StringBuffer buf = new StringBuffer((int) 1.2 * str.length() * (listSize - i) / listSize); |
| while (tok.hasMoreTokens()) { |
| buf.append(tok.nextToken()); |
| if (tok.hasMoreTokens()) { |
| buf.append(separator); |
| } |
| } |
| list[i] = buf.toString(); |
| break; |
| } else { |
| list[i] = tok.nextToken(); |
| } |
| i++; |
| } |
| return list; |
| } |
| |
| // Joining |
| //-------------------------------------------------------------------------- |
| /** |
| * Concatenates elements of an array into a single string. |
| * The difference from join is that concatenate has no delimiter. |
| * |
| * @param array the array of values to concatenate. |
| * @return the concatenated string. |
| */ |
| public static String concatenate(Object[] array) { |
| return join(array, ""); |
| } |
| |
| /** |
| * Joins the elements of the provided array into a single string |
| * containing the provided list of elements. |
| * No delimiter is added before or after the list. |
| * A null separator is the same as a blank String. |
| * |
| * @param array the array of values to join together |
| * @param separator the separator character to use |
| * @return the joined String |
| */ |
| public static String join(Object[] array, String separator) { |
| if (separator == null) { |
| separator = ""; |
| } |
| int arraySize = array.length; |
| int bufSize = (arraySize == 0 ? 0 : (array[0].toString().length() + |
| separator.length()) * arraySize); |
| StringBuffer buf = new StringBuffer(bufSize); |
| |
| for (int i = 0; i < arraySize; i++) { |
| if (i > 0) { |
| buf.append(separator); |
| } |
| buf.append(array[i]); |
| } |
| return buf.toString(); |
| } |
| |
| /** |
| * Joins the elements of the provided iterator into a single string |
| * containing the provided elements. |
| * No delimiter is added before or after the list. |
| * A null separator is the same as a blank String. |
| * |
| * @param iterator the iterator of values to join together |
| * @param separator the separator character to use |
| * @return the joined String |
| */ |
| public static String join(Iterator iterator, String separator) { |
| if (separator == null) { |
| separator = ""; |
| } |
| StringBuffer buf = new StringBuffer(256); // Java default is 16, probably too small |
| while (iterator.hasNext()) { |
| buf.append(iterator.next()); |
| if (iterator.hasNext()) { |
| buf.append(separator); |
| } |
| } |
| return buf.toString(); |
| } |
| |
| |
| |
| // Replacing |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Replace a string with another string inside a larger string, once. |
| * |
| * @see #replace(String text, String repl, String with, int max) |
| * @param text text to search and replace in |
| * @param repl String to search for |
| * @param with String to replace with |
| * @return the text with any replacements processed |
| */ |
| public static String replaceOnce(String text, String repl, String with) { |
| return replace(text, repl, with, 1); |
| } |
| |
| /** |
| * Replace all occurances of a string within another string. |
| * |
| * @see #replace(String text, String repl, String with, int max) |
| * @param text text to search and replace in |
| * @param repl String to search for |
| * @param with String to replace with |
| * @return the text with any replacements processed |
| */ |
| public static String replace(String text, String repl, String with) { |
| return replace(text, repl, with, -1); |
| } |
| |
| /** |
| * Replace a string with another string inside a larger string, |
| * for the first <code>max</code> values of the search string. A |
| * <code>null</code> reference is passed to this method is a |
| * no-op. |
| * |
| * @param text text to search and replace in |
| * @param repl String to search for |
| * @param with String to replace with |
| * @param max maximum number of values to replace, or |
| * <code>-1</code> if no maximum |
| * @return the text with any replacements processed |
| * @throws NullPointerException if repl is null |
| */ |
| public static String replace(String text, String repl, String with, |
| int max) { |
| if (text == null) { |
| return null; |
| } |
| |
| StringBuffer buf = new StringBuffer(text.length()); |
| int start = 0, end = 0; |
| while ((end = text.indexOf(repl, start)) != -1) { |
| buf.append(text.substring(start, end)).append(with); |
| start = end + repl.length(); |
| |
| if (--max == 0) { |
| break; |
| } |
| } |
| buf.append(text.substring(start)); |
| return buf.toString(); |
| } |
| |
| /** |
| * Overlay a part of a string with another string. |
| * |
| * @param text String to do overlaying in |
| * @param overlay String to overlay |
| * @param start int to start overlaying at |
| * @param end int to stop overlaying before |
| * @return String with overlayed text |
| * @throws NullPointerException if text or overlay is null |
| */ |
| public static String overlayString(String text, String overlay, int start, int end) { |
| return new StringBuffer(start + overlay.length() + text.length() - end + 1) |
| .append(text.substring(0, start)) |
| .append(overlay) |
| .append(text.substring(end)) |
| .toString(); |
| } |
| |
| // Centering |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Center a string in a larger string of size n. |
| * Uses spaces as the value to buffer the string with. |
| * Equivalent to <code>center(str, size, "")</code> |
| * |
| * @param str String to center |
| * @param size int size of new String |
| * @return String containing centered String |
| * @throws NullPointerException if str is null |
| */ |
| public static String center(String str, int size) { |
| return center(str, size, " "); |
| } |
| |
| /** |
| * Center a string in a larger string of size n. |
| * Uses a supplied String as the value to buffer the string with.. |
| * |
| * @param str String to center |
| * @param size int size of new String |
| * @param delim String to buffer the new String with |
| * @return String containing centered String |
| * @throws NullPointerException if str or delim is null |
| * @throws ArithmeticException if delim is the empty string |
| */ |
| public static String center(String str, int size, String delim) { |
| int sz = str.length(); |
| int p = size - sz; |
| if (p < 1) { |
| return str; |
| } |
| str = leftPad(str, sz + p / 2, delim); |
| str = rightPad(str, size, delim); |
| return str; |
| } |
| |
| // Chomping |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Remove the last newline, and everything after it from a String. |
| * |
| * @param str String to chomp the newline from |
| * @return String without chomped newline |
| * @throws NullPointerException if str is null |
| */ |
| public static String chomp(String str) { |
| return chomp(str, "\n"); |
| } |
| |
| /** |
| * Remove the last value of a supplied String, and everything after it |
| * from a String. |
| * |
| * @param str String to chomp from |
| * @param sep String to chomp |
| * @return String without chomped ending |
| * @throws NullPointerException if str or sep is null |
| */ |
| public static String chomp(String str, String sep) { |
| int idx = str.lastIndexOf(sep); |
| if (idx != -1) { |
| return str.substring(0, idx); |
| } else { |
| return str; |
| } |
| } |
| |
| /** |
| * Remove a newline if and only if it is at the end |
| * of the supplied string. |
| * |
| * @param str String to chomp from |
| * @return String without chomped ending |
| * @throws NullPointerException if str is null |
| */ |
| public static String chompLast(String str) { |
| return chompLast(str, "\n"); |
| } |
| |
| /** |
| * Remove a value if and only if the string ends with that value. |
| * |
| * @param str String to chomp from |
| * @param sep String to chomp |
| * @return String without chomped ending |
| * @throws NullPointerException if str or sep is null |
| */ |
| public static String chompLast(String str, String sep) { |
| if (str.length() == 0) { |
| return str; |
| } |
| String sub = str.substring(str.length() - sep.length()); |
| if (sep.equals(sub)) { |
| return str.substring(0, str.length() - sep.length()); |
| } else { |
| return str; |
| } |
| } |
| |
| /** |
| * Remove everything and return the last value of a supplied String, and |
| * everything after it from a String. |
| * |
| * @param str String to chomp from |
| * @param sep String to chomp |
| * @return String chomped |
| * @throws NullPointerException if str or sep is null |
| */ |
| public static String getChomp(String str, String sep) { |
| int idx = str.lastIndexOf(sep); |
| if (idx == str.length() - sep.length()) { |
| return sep; |
| } else if (idx != -1) { |
| return str.substring(idx); |
| } else { |
| return ""; |
| } |
| } |
| |
| /** |
| * Remove the first value of a supplied String, and everything before it |
| * from a String. |
| * |
| * @param str String to chomp from |
| * @param sep String to chomp |
| * @return String without chomped beginning |
| * @throws NullPointerException if str or sep is null |
| */ |
| public static String prechomp(String str, String sep) { |
| int idx = str.indexOf(sep); |
| if (idx != -1) { |
| return str.substring(idx + sep.length()); |
| } else { |
| return str; |
| } |
| } |
| |
| /** |
| * Remove and return everything before the first value of a |
| * supplied String from another String. |
| * |
| * @param str String to chomp from |
| * @param sep String to chomp |
| * @return String prechomped |
| * @throws NullPointerException if str or sep is null |
| */ |
| public static String getPrechomp(String str, String sep) { |
| int idx = str.indexOf(sep); |
| if (idx != -1) { |
| return str.substring(0, idx + sep.length()); |
| } else { |
| return ""; |
| } |
| } |
| |
| // Chopping |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Remove the last character from a String. If the String |
| * ends in \r\n, then remove both of them. |
| * |
| * @param str String to chop last character from |
| * @return String without last character |
| * @throws NullPointerException if str is null |
| */ |
| public static String chop(String str) { |
| if ("".equals(str)) { |
| return ""; |
| } |
| if (str.length() == 1) { |
| return ""; |
| } |
| int lastIdx = str.length() - 1; |
| String ret = str.substring(0, lastIdx); |
| char last = str.charAt(lastIdx); |
| if (last == '\n') { |
| if (ret.charAt(lastIdx - 1) == '\r') { |
| return ret.substring(0, lastIdx - 1); |
| } |
| } |
| return ret; |
| } |
| |
| /** |
| * Remove \n from end of a String if it's there. |
| * If a \r precedes it, then remove that too. |
| * |
| * @param str String to chop a newline from |
| * @return String without newline |
| * @throws NullPointerException if str is null |
| */ |
| public static String chopNewline(String str) { |
| int lastIdx = str.length() - 1; |
| char last = str.charAt(lastIdx); |
| if (last == '\n') { |
| if (str.charAt(lastIdx - 1) == '\r') { |
| lastIdx--; |
| } |
| } else { |
| lastIdx++; |
| } |
| return str.substring(0, lastIdx); |
| } |
| |
| |
| // Conversion |
| //-------------------------------------------------------------------------- |
| |
| // spec 3.10.6 |
| /** |
| * Escapes any values it finds into their String form. |
| * So a tab becomes the characters '\\' and 't'. |
| * |
| * @param str String to escape values in |
| * |
| * @return String with escaped values |
| * @throws NullPointerException if str is null |
| */ |
| public static String escape(String str) { |
| // improved with code from cybertiger@cyberiantiger.org |
| // unicode from him, and defaul for < 32's. |
| int sz = str.length(); |
| StringBuffer buffer = new StringBuffer(2 * sz); |
| for (int i = 0; i < sz; i++) { |
| char ch = str.charAt(i); |
| |
| // handle unicode |
| if (ch > 0xfff) { |
| buffer.append("\\u" + Integer.toHexString(ch)); |
| } else if (ch > 0xff) { |
| buffer.append("\\u0" + Integer.toHexString(ch)); |
| } else if (ch > 0x7f) { |
| buffer.append("\\u00" + Integer.toHexString(ch)); |
| } else if (ch < 32) { |
| switch (ch) { |
| case '\b' : |
| buffer.append('\\'); |
| buffer.append('b'); |
| break; |
| case '\n' : |
| buffer.append('\\'); |
| buffer.append('n'); |
| break; |
| case '\t' : |
| buffer.append('\\'); |
| buffer.append('t'); |
| break; |
| case '\f' : |
| buffer.append('\\'); |
| buffer.append('f'); |
| break; |
| case '\r' : |
| buffer.append('\\'); |
| buffer.append('r'); |
| break; |
| default : |
| if (ch > 0xf) { |
| buffer.append("\\u00" + Integer.toHexString(ch)); |
| } else { |
| buffer.append("\\u000" + Integer.toHexString(ch)); |
| } |
| break; |
| } |
| } else { |
| switch (ch) { |
| case '\'' : |
| buffer.append('\\'); |
| buffer.append('\''); |
| break; |
| case '"' : |
| buffer.append('\\'); |
| buffer.append('"'); |
| break; |
| case '\\' : |
| buffer.append('\\'); |
| buffer.append('\\'); |
| break; |
| default : |
| buffer.append(ch); |
| break; |
| } |
| } |
| } |
| return buffer.toString(); |
| } |
| |
| // Padding |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Repeat a string n times to form a new string. |
| * |
| * @param str String to repeat |
| * @param repeat int number of times to repeat |
| * @return String with repeated string |
| * @throws NegativeArraySizeException if repeat < 0 |
| * @throws NullPointerException if str is null |
| */ |
| public static String repeat(String str, int repeat) { |
| StringBuffer buffer = new StringBuffer(repeat * str.length()); |
| for (int i = 0; i < repeat; i++) { |
| buffer.append(str); |
| } |
| return buffer.toString(); |
| } |
| |
| /** |
| * Right pad a String with spaces. Pad to a size of n. |
| * |
| * @param str String to repeat |
| * @param size int number of times to repeat |
| * @return right padded String |
| * @throws NullPointerException if str is null |
| */ |
| public static String rightPad(String str, int size) { |
| return rightPad(str, size, " "); |
| } |
| |
| /** |
| * Right pad a String with a specified string. Pad to a size of n. |
| * |
| * @param str String to pad out |
| * @param size int size to pad to |
| * @param delim String to pad with |
| * @return right padded String |
| * @throws NullPointerException if str or delim is null |
| * @throws ArithmeticException if delim is the empty string |
| */ |
| public static String rightPad(String str, int size, String delim) { |
| size = (size - str.length()) / delim.length(); |
| if (size > 0) { |
| str += repeat(delim, size); |
| } |
| return str; |
| } |
| |
| /** |
| * Left pad a String with spaces. Pad to a size of n. |
| * |
| * @param str String to pad out |
| * @param size int size to pad to |
| * @return left padded String |
| * @throws NullPointerException if str or delim is null |
| */ |
| public static String leftPad(String str, int size) { |
| return leftPad(str, size, " "); |
| } |
| /** |
| * Left pad a String with a specified string. Pad to a size of n. |
| * |
| * @param str String to pad out |
| * @param size int size to pad to |
| * @param delim String to pad with |
| * @return left padded String |
| * @throws NullPointerException if str or delim is null |
| * @throws ArithmeticException if delim is the empty string |
| */ |
| public static String leftPad(String str, int size, String delim) { |
| size = (size - str.length()) / delim.length(); |
| if (size > 0) { |
| str = repeat(delim, size) + str; |
| } |
| return str; |
| } |
| |
| // Stripping |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Remove whitespace from the front and back of a String. |
| * |
| * @param str the string to remove whitespace from |
| * @return the stripped string |
| */ |
| public static String strip(String str) { |
| return strip(str, null); |
| } |
| /** |
| * Remove a specified String from the front and back of a |
| * String. If Whitespace is wanted to be removed, used the |
| * strip(String) method. |
| * |
| * @param str the string to remove a string from |
| * @param delim the string to remove at start and end |
| * @return the stripped string |
| */ |
| public static String strip(String str, String delim) { |
| str = stripStart(str, delim); |
| return stripEnd(str, delim); |
| } |
| |
| /** |
| * Strip whitespace from the front and back of every string |
| * in the array. |
| * |
| * @param strs the strings to remove whitespace from |
| * @return the stripped strings |
| */ |
| public static String[] stripAll(String[] strs) { |
| return stripAll(strs, null); |
| } |
| |
| /** |
| * Strip the specified delimiter from the front and back of |
| * every String in the array. |
| * |
| * @param strs the strings to remove a string from |
| * @param delimiter the string to remove at start and end |
| * @return the stripped strings |
| */ |
| public static String[] stripAll(String[] strs, String delimiter) { |
| if ((strs == null) || (strs.length == 0)) { |
| return strs; |
| } |
| int sz = strs.length; |
| String[] newArr = new String[sz]; |
| for (int i = 0; i < sz; i++) { |
| newArr[i] = strip(strs[i], delimiter); |
| } |
| return newArr; |
| } |
| |
| /** |
| * Strip any of a supplied string from the end of a String.. |
| * If the strip string is null, whitespace is stripped. |
| * |
| * @param str the string to remove characters from |
| * @param strip the string to remove |
| * @return the stripped string |
| */ |
| public static String stripEnd(String str, String strip) { |
| if (str == null) { |
| return null; |
| } |
| int end = str.length(); |
| |
| if (strip == null) { |
| while ((end != 0) && Character.isWhitespace(str.charAt(end - 1))) { |
| end--; |
| } |
| } else { |
| while ((end != 0) && (strip.indexOf(str.charAt(end - 1)) != -1)) { |
| end--; |
| } |
| } |
| return str.substring(0, end); |
| } |
| |
| /** |
| * Strip any of a supplied string from the start of a String. |
| * If the strip string is null, whitespace is stripped. |
| * |
| * @param str the string to remove characters from |
| * @param strip the string to remove |
| * @return the stripped string |
| */ |
| public static String stripStart(String str, String strip) { |
| if (str == null) { |
| return null; |
| } |
| |
| int start = 0; |
| |
| int sz = str.length(); |
| |
| if (strip == null) { |
| while ((start != sz) && Character.isWhitespace(str.charAt(start))) { |
| start++; |
| } |
| } else { |
| char chr = strip.charAt(0); |
| while ((start != sz) && (strip.indexOf(str.charAt(start)) != -1)) { |
| start++; |
| } |
| } |
| return str.substring(start); |
| } |
| |
| // Case conversion |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Convert a String to upper case, null string returns null. |
| * |
| * @param str the string to uppercase |
| * @return the upper cased string |
| */ |
| public static String upperCase(String str) { |
| if (str == null) { |
| return null; |
| } |
| return str.toUpperCase(); |
| } |
| |
| /** |
| * Convert a String to lower case, null string returns null. |
| * |
| * @param str the string to lowercase |
| * @return the lower cased string |
| */ |
| public static String lowerCase(String str) { |
| if (str == null) { |
| return null; |
| } |
| return str.toLowerCase(); |
| } |
| |
| /** |
| * Uncapitalise a string. That is, convert the first character into |
| * lower-case. Null is returned as null. |
| * |
| * @param str the string to uncapitalise |
| * @return uncapitalised string |
| */ |
| public static String uncapitalise(String str) { |
| if (str == null) { |
| return null; |
| } |
| if (str.length() == 0) { |
| return ""; |
| } |
| return new StringBuffer(str.length()) |
| .append(Character.toLowerCase(str.charAt(0))) |
| .append(str.substring(1)) |
| .toString(); |
| } |
| |
| /** |
| * Capitalise a string. That is, convert the first character into |
| * title-case. Null is returned as null. |
| * |
| * @param str the string to capitalise |
| * @return capitalised string |
| */ |
| public static String capitalise(String str) { |
| if (str == null) { |
| return null; |
| } |
| if (str.length() == 0) { |
| return ""; |
| } |
| return new StringBuffer(str.length()) |
| .append(Character.toTitleCase(str.charAt(0))) |
| .append(str.substring(1)) |
| .toString(); |
| } |
| |
| /** |
| * Swaps the case of String. Properly looks after |
| * making sure the start of words are Titlecase and not |
| * Uppercase. Null is returned as null. |
| * |
| * @param str the string to swap the case of |
| * @return the modified string |
| */ |
| public static String swapCase(String str) { |
| if (str == null) { |
| return null; |
| } |
| int sz = str.length(); |
| StringBuffer buffer = new StringBuffer(sz); |
| |
| boolean whitespace = false; |
| char ch = 0; |
| char tmp = 0; |
| |
| for (int i = 0; i < sz; i++) { |
| ch = str.charAt(i); |
| if (Character.isUpperCase(ch)) { |
| tmp = Character.toLowerCase(ch); |
| } else if (Character.isTitleCase(ch)) { |
| tmp = Character.toLowerCase(ch); |
| } else if (Character.isLowerCase(ch)) { |
| if (whitespace) { |
| tmp = Character.toTitleCase(ch); |
| } else { |
| tmp = Character.toUpperCase(ch); |
| } |
| } else { |
| tmp = ch; |
| } |
| buffer.append(tmp); |
| whitespace = Character.isWhitespace(ch); |
| } |
| return buffer.toString(); |
| } |
| |
| |
| /** |
| * Capitalise all the words in a string. Uses Character.isWhitespace |
| * as a separator between words. Null will return null. |
| * |
| * @param str the string to capitalise |
| * @return capitalised string |
| */ |
| public static String capitaliseAllWords(String str) { |
| if (str == null) { |
| return null; |
| } |
| int sz = str.length(); |
| StringBuffer buffer = new StringBuffer(sz); |
| boolean space = true; |
| for (int i = 0; i < sz; i++) { |
| char ch = str.charAt(i); |
| if (Character.isWhitespace(ch)) { |
| buffer.append(ch); |
| space = true; |
| } else if (space) { |
| buffer.append(Character.toTitleCase(ch)); |
| space = false; |
| } else { |
| buffer.append(ch); |
| } |
| } |
| return buffer.toString(); |
| } |
| |
| // Nested extraction |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Get the String that is nested in between two instances of the |
| * same String. If str is null, will return null |
| * |
| * @param str the string containing nested-string |
| * @param tag the string before and after nested-string |
| * @return the string that was nested, or null |
| * @throws NullPointerException if tag is null |
| */ |
| public static String getNestedString(String str, String tag) { |
| return getNestedString(str, tag, tag); |
| } |
| |
| /** |
| * Get the string that is nested in between two strings. |
| * |
| * @param str the string containing nested-string |
| * @param open the string before nested-string |
| * @param close the string after nested-string |
| * @return the string that was nested, or null |
| * @throws NullPointerException if open or close is null |
| */ |
| public static String getNestedString(String str, String open, String close) { |
| if (str == null) { |
| return null; |
| } |
| int start = str.indexOf(open); |
| if (start != -1) { |
| int end = str.indexOf(close, start + open.length()); |
| if (end != -1) { |
| return str.substring(start + open.length(), end); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * How many times is the substring in the larger string. |
| * Null returns 0. |
| * |
| * @param str the string to check |
| * @param sub the substring to count |
| * @return the number of occurances, 0 if the string is null |
| * @throws NullPointerException if sub is null |
| */ |
| public static int countMatches(String str, String sub) { |
| if (str == null) { |
| return 0; |
| } |
| int count = 0; |
| int idx = 0; |
| while ((idx = str.indexOf(sub, idx)) != -1) { |
| count++; |
| idx += sub.length(); |
| } |
| return count; |
| } |
| |
| // Character Tests |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Checks if the string contains only unicode letters. |
| * Null will return false. The empty string will return true. |
| * |
| * @param str the string to check |
| * @return true if only contains letters, and is non-null |
| */ |
| public static boolean isAlpha(String str) { |
| if (str == null) { |
| return false; |
| } |
| int sz = str.length(); |
| for (int i = 0; i < sz; i++) { |
| if (Character.isLetter(str.charAt(i)) == false) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Checks if the string contains only unicode letters and space (' '). |
| * Null will return false. The empty string will return true. |
| * |
| * @param str the string to check |
| * @return true if only contains letters and space, and is non-null |
| */ |
| public static boolean isAlphaSpace(String str) { |
| if (str == null) { |
| return false; |
| } |
| int sz = str.length(); |
| for (int i = 0; i < sz; i++) { |
| if ((Character.isLetter(str.charAt(i)) == false) && |
| (str.charAt(i) != ' ')) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Checks if the string contains only unicode letters or digits. |
| * Null will return false. The empty string will return true. |
| * |
| * @param str the string to check |
| * @return true if only contains letters or digits, and is non-null |
| */ |
| public static boolean isAlphanumeric(String str) { |
| if (str == null) { |
| return false; |
| } |
| int sz = str.length(); |
| for (int i = 0; i < sz; i++) { |
| if (Character.isLetterOrDigit(str.charAt(i)) == false) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Checks if the string contains only unicode letters, digits or space (' '). |
| * Null will return false. The empty string will return true. |
| * |
| * @param str the string to check |
| * @return true if only contains letters, digits or space, and is non-null |
| */ |
| public static boolean isAlphanumericSpace(String str) { |
| if (str == null) { |
| return false; |
| } |
| int sz = str.length(); |
| for (int i = 0; i < sz; i++) { |
| if ((Character.isLetterOrDigit(str.charAt(i)) == false) && |
| (str.charAt(i) != ' ')) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Checks if the string contains only unicode digits. |
| * Null will return false. The empty string will return true. |
| * |
| * @param str the string to check |
| * @return true if only contains digits, and is non-null |
| */ |
| public static boolean isNumeric(String str) { |
| if (str == null) { |
| return false; |
| } |
| int sz = str.length(); |
| for (int i = 0; i < sz; i++) { |
| if (Character.isDigit(str.charAt(i)) == false) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Checks if the string contains only unicode digits or space (' '). |
| * Null will return false. The empty string will return true. |
| * |
| * @param str the string to check |
| * @return true if only contains digits or space, and is non-null |
| */ |
| public static boolean isNumericSpace(String str) { |
| if (str == null) { |
| return false; |
| } |
| int sz = str.length(); |
| for (int i = 0; i < sz; i++) { |
| if ((Character.isDigit(str.charAt(i)) == false) && |
| (str.charAt(i) != ' ')) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| // Defaults |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Return either the passed in String, or if it is null, |
| * then an empty String. |
| * |
| * @param str the string to check |
| * @return the passed in string, or blank if it was null |
| */ |
| public static String defaultString(String str) { |
| return defaultString(str, ""); |
| } |
| |
| /** |
| * Return either the passed in String, or if it is null, |
| * then a passed in default String. |
| * |
| * @param str the string to check |
| * @param defaultString the default string to return is str is null |
| * @return the passed in string, or the default if it was null |
| */ |
| public static String defaultString(String str, String defaultString) { |
| return (str == null) ? defaultString : str; |
| } |
| |
| // Reversing |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Reverse a String, null string returns null. |
| * |
| * @param str the string to reverse |
| * @return the reversed string |
| */ |
| public static String reverse(String str) { |
| if (str == null) { |
| return null; |
| } |
| return new StringBuffer(str).reverse().toString(); |
| } |
| |
| /** |
| * Reverses a string that is delimited by a specific character. |
| * The strings between the delimiters are not reversed. |
| * Thus java.lang.String becomes String.lang.java (if the delimiter is '.'). |
| * |
| * @param str the string to reverse |
| * @param delimiter the delimiter to use |
| * @return the reversed string |
| */ |
| public static String reverseDelimitedString(String str, String delimiter) { |
| // could implement manually, but simple way is to reuse other, |
| // probably slower, methods. |
| String[] strs = split(str, delimiter); |
| reverseArray(strs); |
| return join(strs, delimiter); |
| } |
| |
| /** |
| * Reverses an array. |
| * TAKEN FROM CollectionsUtils. |
| * @param array the array to reverse |
| */ |
| private static void reverseArray(Object[] array) { |
| int i = 0; |
| int j = array.length - 1; |
| Object tmp; |
| |
| while (j > i) { |
| tmp = array[j]; |
| array[j] = array[i]; |
| array[i] = tmp; |
| j--; |
| i++; |
| } |
| } |
| |
| |
| // Misc |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Find the Levenshtein distance between two strings. |
| * This is the number of changes needed to change one string into |
| * another. Where each change is a single character modification. |
| * |
| * This implemmentation of the levenshtein distance algorithm |
| * is from http://www.merriampark.com/ld.htm |
| * |
| * @param s the first String |
| * @param t the second String |
| * @return int result distance |
| * @throws NullPointerException if s or t is null |
| */ |
| public static int getLevenshteinDistance(String s, String t) { |
| int d[][]; // matrix |
| int n; // length of s |
| int m; // length of t |
| int i; // iterates through s |
| int j; // iterates through t |
| char s_i; // ith character of s |
| char t_j; // jth character of t |
| int cost; // cost |
| |
| // Step 1 |
| n = s.length(); |
| m = t.length(); |
| if (n == 0) { |
| return m; |
| } |
| if (m == 0) { |
| return n; |
| } |
| d = new int[n + 1][m + 1]; |
| |
| // Step 2 |
| for (i = 0; i <= n; i++) { |
| d[i][0] = i; |
| } |
| |
| for (j = 0; j <= m; j++) { |
| d[0][j] = j; |
| } |
| |
| // Step 3 |
| for (i = 1; i <= n; i++) { |
| s_i = s.charAt(i - 1); |
| |
| // Step 4 |
| for (j = 1; j <= m; j++) { |
| t_j = t.charAt(j - 1); |
| |
| // Step 5 |
| if (s_i == t_j) { |
| cost = 0; |
| } else { |
| cost = 1; |
| } |
| |
| // Step 6 |
| d[i][j] = NumberUtils.minimum(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost); |
| } |
| } |
| |
| // Step 7 |
| return d[n][m]; |
| } |
| |
| /** |
| * Checks if the String contains only certain chars. |
| * |
| * @param str the String to check |
| * @param valid an array of valid chars |
| * @return true if it only contains valid chars and is non-null |
| */ |
| public static boolean containsOnly(String str, char[] valid) { |
| if (str == null || valid == null) { |
| return false; |
| } |
| |
| int strSize = str.length(); |
| int validSize = valid.length; |
| |
| for (int i = 0; i < strSize; i++) { |
| boolean contains = false; |
| for (int j = 0; j < validSize; j++) { |
| if (valid[j] == str.charAt(i)) { |
| contains = true; |
| break; |
| } |
| } |
| if (!contains) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| } |