All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jooq.tools.StringUtils Maven / Gradle / Ivy

There is a newer version: 0.10.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jooq.tools;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * 

* Operations on {@link java.lang.String} that are null safe. *

*
    *
  • IsEmpty/IsBlank - checks if a String contains text
  • *
  • Trim/Strip - removes leading and trailing whitespace
  • *
  • Equals - compares two strings null-safe
  • *
  • startsWith - check if a String starts with a prefix null-safe
  • *
  • endsWith - check if a String ends with a suffix null-safe
  • *
  • IndexOf/LastIndexOf/Contains - null-safe index-of checks *
  • IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut - * index-of any of a set of Strings
  • *
  • ContainsOnly/ContainsNone/ContainsAny - does String contains * only/none/any of these characters
  • *
  • Substring/Left/Right/Mid - null-safe substring extractions
  • *
  • SubstringBefore/SubstringAfter/SubstringBetween - substring * extraction relative to other strings
  • *
  • Split/Join - splits a String into an array of substrings and vice * versa
  • *
  • Remove/Delete - removes part of a String
  • *
  • Replace/Overlay - Searches a String and replaces one String with * another
  • *
  • Chomp/Chop - removes the last part of a String
  • *
  • LeftPad/RightPad/Center/Repeat - pads a String
  • *
  • UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize - changes the * case of a String
  • *
  • CountMatches - counts the number of occurrences of one String in * another
  • *
  • IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable - checks the * characters in a String
  • *
  • DefaultString - protects against a null input String
  • *
  • Reverse/ReverseDelimited - reverses a String
  • *
  • Abbreviate - abbreviates a string using ellipsis
  • *
  • Difference - compares Strings and reports on their differences
  • *
  • LevensteinDistance - the number of changes needed to change one * String into another
  • *
*

* The StringUtils class defines certain words related to String * handling. *

*
    *
  • null - null
  • *
  • empty - a zero-length string ("")
  • *
  • space - the space character (' ', char 32)
  • *
  • whitespace - the characters defined by * {@link Character#isWhitespace(char)}
  • *
  • trim - the characters <= 32 as in {@link String#trim()}
  • *
*

* StringUtils handles null input Strings quietly. * That is to say that a null input will return null. * Where a boolean or int is being returned details * vary by method. *

*

* A side effect of the null handling is that a * NullPointerException should be considered a bug in * StringUtils (except for deprecated methods). *

*

* Methods in this class give sample code to explain their operation. The symbol * * is used to indicate any input including null. *

* * @see java.lang.String * @author Apache Software Foundation * @author Apache Jakarta * Turbine * @author Jon S. Stevens * @author Daniel L. Rall * @author Greg Coladonato * @author Ed Korthof * @author Rand McNeely * @author Fredrik Westermarck * @author Holger Krauth * @author Alexander Day Chaffee * @author Henning P. Schmiedehausen * @author Arun Mammen Thomas * @author Gary Gregory * @author Phil Steitz * @author Al Chou * @author Michael Davey * @author Reuben Sivan * @author Chris Hyzer * @author Scott Johnson * @since 1.0 * @version $Id: StringUtils.java 911986 2010-02-19 21:19:05Z niallp $ */ public final class StringUtils { /** * The empty String {@code ""}. * @since 2.0 */ public static final String EMPTY = ""; /** * Represents a failed index search. * @since 2.1 */ public static final int INDEX_NOT_FOUND = -1; /** *

The maximum size to which the padding constant(s) can expand.

*/ private static final int PAD_LIMIT = 8192; // Defaults // ----------------------------------------------------------------------- /** *

* Returns either the passed in String, or if the String is * null, an empty String (""). *

* *
     * StringUtils.defaultString(null)  = ""
     * StringUtils.defaultString("")    = ""
     * StringUtils.defaultString("bat") = "bat"
     * 
* * @see String#valueOf(Object) * @param str the String to check, may be null * @return the passed in String, or the empty String if it was * null */ public static String defaultString(String str) { return str == null ? "" : str; } /** *

Returns either the passed in String, or if the String is * null, the value of defaultStr.

* *
     * StringUtils.defaultString(null, "NULL")  = "NULL"
     * StringUtils.defaultString("", "NULL")    = ""
     * StringUtils.defaultString("bat", "NULL") = "bat"
     * 
* * @see String#valueOf(Object) * @param str the String to check, may be null * @param defaultStr the default String to return * if the input is null, may be null * @return the passed in String, or the default if it was null */ public static String defaultString(String str, String defaultStr) { return str == null ? defaultStr : str; } /** *

Returns either the passed in String, or if the String is * empty or null, the value of defaultStr.

* *
     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
     * 
* * @see StringUtils#defaultString(String, String) * @param str the String to check, may be null * @param defaultStr the default String to return * if the input is empty ("") or null, may be null * @return the passed in String, or the default */ public static String defaultIfEmpty(String str, String defaultStr) { return StringUtils.isEmpty(str) ? defaultStr : str; } /** *

Returns either the passed in CharSequence, or if the CharSequence is * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.

* *
     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
     * StringUtils.defaultIfBlank("", null)      = null
     * 
* @param str the CharSequence to check, may be null * @param defaultStr the default CharSequence to return * if the input is whitespace, empty ("") or {@code null}, may be null * @return the passed in CharSequence, or the default * @see StringUtils#defaultString(String, String) */ public static String defaultIfBlank(String str, String defaultStr) { return StringUtils.isBlank(str) ? defaultStr : str; } // Empty checks // ----------------------------------------------------------------------- /** *

* Checks if a String is empty ("") or null. *

* *
     * StringUtils.isEmpty(null)      = true
     * StringUtils.isEmpty("")        = true
     * StringUtils.isEmpty(" ")       = false
     * StringUtils.isEmpty("bob")     = false
     * StringUtils.isEmpty("  bob  ") = false
     * 
*

* NOTE: This method changed in Lang version 2.0. It no longer trims the * String. That functionality is available in isBlank(). *

* * @param str the String to check, may be null * @return true if the String is empty or null */ public static boolean isEmpty(String str) { return str == null || str.length() == 0; } /** *

* Checks if a String is whitespace, empty ("") or null. *

* *
     * StringUtils.isBlank(null)      = true
     * StringUtils.isBlank("")        = true
     * StringUtils.isBlank(" ")       = true
     * StringUtils.isBlank("bob")     = false
     * StringUtils.isBlank("  bob  ") = false
     * 
* * @param str the String to check, may be null * @return true if the String is null, empty or whitespace * @since 2.0 */ public static boolean isBlank(String str) { int strLen; if (str == null || (strLen = str.length()) == 0) { return true; } for (int i = 0; i < strLen; i++) { if ((Character.isWhitespace(str.charAt(i)) == false)) { return false; } } return true; } // Count matches // ----------------------------------------------------------------------- /** *

* Counts how many times the substring appears in the larger String. *

*

* A null or empty ("") String input returns 0. *

* *
     * StringUtils.countMatches(null, *)       = 0
     * StringUtils.countMatches("", *)         = 0
     * StringUtils.countMatches("abba", null)  = 0
     * StringUtils.countMatches("abba", "")    = 0
     * StringUtils.countMatches("abba", "a")   = 2
     * StringUtils.countMatches("abba", "ab")  = 1
     * StringUtils.countMatches("abba", "xxx") = 0
     * 
* * @param str the String to check, may be null * @param sub the substring to count, may be null * @return the number of occurrences, 0 if either String is * null */ public static int countMatches(String str, String sub) { if (isEmpty(str) || isEmpty(sub)) { return 0; } int count = 0; int idx = 0; while ((idx = str.indexOf(sub, idx)) != -1) { count++; idx += sub.length(); } return count; } // Padding // ----------------------------------------------------------------------- /** *

Right pad a String with spaces (' ').

* *

The String is padded to the size of size.

* *
     * StringUtils.rightPad(null, *)   = null
     * StringUtils.rightPad("", 3)     = "   "
     * StringUtils.rightPad("bat", 3)  = "bat"
     * StringUtils.rightPad("bat", 5)  = "bat  "
     * StringUtils.rightPad("bat", 1)  = "bat"
     * StringUtils.rightPad("bat", -1) = "bat"
     * 
* * @param str the String to pad out, may be null * @param size the size to pad to * @return right padded String or original String if no padding is necessary, * null if null String input */ public static String rightPad(String str, int size) { return rightPad(str, size, ' '); } /** *

Right pad a String with a specified character.

* *

The String is padded to the size of size.

* *
     * StringUtils.rightPad(null, *, *)     = null
     * StringUtils.rightPad("", 3, 'z')     = "zzz"
     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
     * StringUtils.rightPad("bat", -1, 'z') = "bat"
     * 
* * @param str the String to pad out, may be null * @param size the size to pad to * @param padChar the character to pad with * @return right padded String or original String if no padding is necessary, * null if null String input * @since 2.0 */ public static String rightPad(String str, int size, char padChar) { if (str == null) { return null; } int pads = size - str.length(); if (pads <= 0) { return str; // returns original String when possible } if (pads > PAD_LIMIT) { return rightPad(str, size, String.valueOf(padChar)); } return str.concat(padding(pads, padChar)); } /** *

Right pad a String with a specified String.

* *

The String is padded to the size of size.

* *
     * StringUtils.rightPad(null, *, *)      = null
     * StringUtils.rightPad("", 3, "z")      = "zzz"
     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
     * StringUtils.rightPad("bat", -1, "yz") = "bat"
     * StringUtils.rightPad("bat", 5, null)  = "bat  "
     * StringUtils.rightPad("bat", 5, "")    = "bat  "
     * 
* * @param str the String to pad out, may be null * @param size the size to pad to * @param padStr the String to pad with, null or empty treated as single space * @return right padded String or original String if no padding is necessary, * null if null String input */ public static String rightPad(String str, int size, String padStr) { if (str == null) { return null; } if (isEmpty(padStr)) { padStr = " "; } int padLen = padStr.length(); int strLen = str.length(); int pads = size - strLen; if (pads <= 0) { return str; // returns original String when possible } if (padLen == 1 && pads <= PAD_LIMIT) { return rightPad(str, size, padStr.charAt(0)); } if (pads == padLen) { return str.concat(padStr); } else if (pads < padLen) { return str.concat(padStr.substring(0, pads)); } else { char[] padding = new char[pads]; char[] padChars = padStr.toCharArray(); for (int i = 0; i < pads; i++) { padding[i] = padChars[i % padLen]; } return str.concat(new String(padding)); } } /** *

Left pad a String with spaces (' ').

* *

The String is padded to the size of size.

* *
     * StringUtils.leftPad(null, *)   = null
     * StringUtils.leftPad("", 3)     = "   "
     * StringUtils.leftPad("bat", 3)  = "bat"
     * StringUtils.leftPad("bat", 5)  = "  bat"
     * StringUtils.leftPad("bat", 1)  = "bat"
     * StringUtils.leftPad("bat", -1) = "bat"
     * 
* * @param str the String to pad out, may be null * @param size the size to pad to * @return left padded String or original String if no padding is necessary, * null if null String input */ public static String leftPad(String str, int size) { return leftPad(str, size, ' '); } /** *

Left pad a String with a specified character.

* *

Pad to a size of size.

* *
     * StringUtils.leftPad(null, *, *)     = null
     * StringUtils.leftPad("", 3, 'z')     = "zzz"
     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
     * StringUtils.leftPad("bat", -1, 'z') = "bat"
     * 
* * @param str the String to pad out, may be null * @param size the size to pad to * @param padChar the character to pad with * @return left padded String or original String if no padding is necessary, * null if null String input * @since 2.0 */ public static String leftPad(String str, int size, char padChar) { if (str == null) { return null; } int pads = size - str.length(); if (pads <= 0) { return str; // returns original String when possible } if (pads > PAD_LIMIT) { return leftPad(str, size, String.valueOf(padChar)); } return padding(pads, padChar).concat(str); } /** *

Left pad a String with a specified String.

* *

Pad to a size of size.

* *
     * StringUtils.leftPad(null, *, *)      = null
     * StringUtils.leftPad("", 3, "z")      = "zzz"
     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
     * StringUtils.leftPad("bat", -1, "yz") = "bat"
     * StringUtils.leftPad("bat", 5, null)  = "  bat"
     * StringUtils.leftPad("bat", 5, "")    = "  bat"
     * 
* * @param str the String to pad out, may be null * @param size the size to pad to * @param padStr the String to pad with, null or empty treated as single space * @return left padded String or original String if no padding is necessary, * null if null String input */ public static String leftPad(String str, int size, String padStr) { if (str == null) { return null; } if (isEmpty(padStr)) { padStr = " "; } int padLen = padStr.length(); int strLen = str.length(); int pads = size - strLen; if (pads <= 0) { return str; // returns original String when possible } if (padLen == 1 && pads <= PAD_LIMIT) { return leftPad(str, size, padStr.charAt(0)); } if (pads == padLen) { return padStr.concat(str); } else if (pads < padLen) { return padStr.substring(0, pads).concat(str); } else { char[] padding = new char[pads]; char[] padChars = padStr.toCharArray(); for (int i = 0; i < pads; i++) { padding[i] = padChars[i % padLen]; } return new String(padding).concat(str); } } /** *

Returns padding using the specified delimiter repeated * to a given length.

* *
     * StringUtils.padding(0, 'e')  = ""
     * StringUtils.padding(3, 'e')  = "eee"
     * StringUtils.padding(-2, 'e') = IndexOutOfBoundsException
     * 
* *

Note: this method doesn't not support padding with * Unicode Supplementary Characters * as they require a pair of chars to be represented. * If you are needing to support full I18N of your applications * consider using {@link #repeat(String, int)} instead. *

* * @param repeat number of times to repeat delim * @param padChar character to repeat * @return String with repeated character * @throws IndexOutOfBoundsException if repeat < 0 */ private static String padding(int repeat, char padChar) throws IndexOutOfBoundsException { if (repeat < 0) { throw new IndexOutOfBoundsException("Cannot pad a negative amount: " + repeat); } final char[] buf = new char[repeat]; for (int i = 0; i < buf.length; i++) { buf[i] = padChar; } return new String(buf); } // Abbreviating //----------------------------------------------------------------------- /** *

Abbreviates a String using ellipses. This will turn * "Now is the time for all good men" into "Now is the time for..."

* *

Specifically: *

    *
  • If str is less than maxWidth characters * long, return it.
  • *
  • Else abbreviate it to (substring(str, 0, max-3) + "...").
  • *
  • If maxWidth is less than 4, throw an * IllegalArgumentException.
  • *
  • In no case will it return a String of length greater than * maxWidth.
  • *
*

* *
     * StringUtils.abbreviate(null, *)      = null
     * StringUtils.abbreviate("", 4)        = ""
     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
     * StringUtils.abbreviate("abcdefg", 4) = "a..."
     * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
     * 
* * @param str the String to check, may be null * @param maxWidth maximum length of result String, must be at least 4 * @return abbreviated String, null if null String input * @throws IllegalArgumentException if the width is too small * @since 2.0 */ public static String abbreviate(String str, int maxWidth) { return abbreviate(str, 0, maxWidth); } /** *

Abbreviates a String using ellipses. This will turn * "Now is the time for all good men" into "...is the time for..."

* *

Works like abbreviate(String, int), but allows you to specify * a "left edge" offset. Note that this left edge is not necessarily going to * be the leftmost character in the result, or the first character following the * ellipses, but it will appear somewhere in the result. * *

In no case will it return a String of length greater than * maxWidth.

* *
     * StringUtils.abbreviate(null, *, *)                = null
     * StringUtils.abbreviate("", 0, 4)                  = ""
     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
     * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
     * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
     * 
* * @param str the String to check, may be null * @param offset left edge of source String * @param maxWidth maximum length of result String, must be at least 4 * @return abbreviated String, null if null String input * @throws IllegalArgumentException if the width is too small * @since 2.0 */ public static String abbreviate(String str, int offset, int maxWidth) { if (str == null) { return null; } if (maxWidth < 4) { throw new IllegalArgumentException("Minimum abbreviation width is 4"); } if (str.length() <= maxWidth) { return str; } if (offset > str.length()) { offset = str.length(); } if ((str.length() - offset) < (maxWidth - 3)) { offset = str.length() - (maxWidth - 3); } if (offset <= 4) { return str.substring(0, maxWidth - 3) + "..."; } if (maxWidth < 7) { throw new IllegalArgumentException("Minimum abbreviation width with offset is 7"); } if ((offset + (maxWidth - 3)) < str.length()) { return "..." + abbreviate(str.substring(offset), maxWidth - 3); } return "..." + str.substring(str.length() - (maxWidth - 3)); } // ContainsAny //----------------------------------------------------------------------- /** *

Checks if the String contains any character in the given * set of characters.

* *

A null String will return false. * A null or zero length search array will return false.

* *
     * StringUtils.containsAny(null, *)                = false
     * StringUtils.containsAny("", *)                  = false
     * StringUtils.containsAny(*, null)                = false
     * StringUtils.containsAny(*, [])                  = false
     * StringUtils.containsAny("zzabyycdxx",['z','a']) = true
     * StringUtils.containsAny("zzabyycdxx",['b','y']) = true
     * StringUtils.containsAny("aba", ['z'])           = false
     * 
* * @param str the String to check, may be null * @param searchChars the chars to search for, may be null * @return the true if any of the chars are found, * false if no match or null input * @since 2.4 */ public static boolean containsAny(String str, char... searchChars) { if (str == null || str.length() == 0 || searchChars == null || searchChars.length == 0) { return false; } for (int i = 0; i < str.length(); i++) { char ch = str.charAt(i); for (int j = 0; j < searchChars.length; j++) { if (searchChars[j] == ch) { return true; } } } return false; } /** *

Replaces all occurrences of a String within another String.

* *

A {@code null} reference passed to this method is a no-op.

* *
     * StringUtils.replace(null, *, *)        = null
     * StringUtils.replace("", *, *)          = ""
     * StringUtils.replace("any", null, *)    = "any"
     * StringUtils.replace("any", *, null)    = "any"
     * StringUtils.replace("any", "", *)      = "any"
     * StringUtils.replace("aba", "a", null)  = "aba"
     * StringUtils.replace("aba", "a", "")    = "b"
     * StringUtils.replace("aba", "a", "z")   = "zbz"
     * 
* * @see #replace(String text, String searchString, String replacement, int max) * @param text text to search and replace in, may be null * @param searchString the String to search for, may be null * @param replacement the String to replace it with, may be null * @return the text with any replacements processed, * {@code null} if null String input */ public static String replace(String text, String searchString, String replacement) { return replace(text, searchString, replacement, -1); } /** *

Replaces a String with another String inside a larger String, * for the first {@code max} values of the search String.

* *

A {@code null} reference passed to this method is a no-op.

* *
     * StringUtils.replace(null, *, *, *)         = null
     * StringUtils.replace("", *, *, *)           = ""
     * StringUtils.replace("any", null, *, *)     = "any"
     * StringUtils.replace("any", *, null, *)     = "any"
     * StringUtils.replace("any", "", *, *)       = "any"
     * StringUtils.replace("any", *, *, 0)        = "any"
     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
     * StringUtils.replace("abaa", "a", "", -1)   = "b"
     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
     * 
* * @param text text to search and replace in, may be null * @param searchString the String to search for, may be null * @param replacement the String to replace it with, may be null * @param max maximum number of values to replace, or {@code -1} if no maximum * @return the text with any replacements processed, * {@code null} if null String input */ public static String replace(String text, String searchString, String replacement, int max) { if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) { return text; } int start = 0; int end = text.indexOf(searchString, start); if (end == INDEX_NOT_FOUND) { return text; } int replLength = searchString.length(); int increase = replacement.length() - replLength; increase = (increase < 0 ? 0 : increase); increase *= (max < 0 ? 16 : (max > 64 ? 64 : max)); StringBuilder buf = new StringBuilder(text.length() + increase); while (end != INDEX_NOT_FOUND) { buf.append(text.substring(start, end)).append(replacement); start = end + replLength; if (--max == 0) { break; } end = text.indexOf(searchString, start); } buf.append(text.substring(start)); return buf.toString(); } /** *

* Replaces all occurrences of Strings within another String. *

* *

* A null reference passed to this method is a no-op, or if * any "search string" or "string to replace" is null, that replace will be * ignored. This will not repeat. For repeating replaces, call the * overloaded method. *

* *
     *  StringUtils.replaceEach(null, *, *)        = null
     *  StringUtils.replaceEach("", *, *)          = ""
     *  StringUtils.replaceEach("aba", null, null) = "aba"
     *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
     *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
     *  (example of how it does not repeat)
     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
     * 
* * @param text * text to search and replace in, no-op if null * @param searchList * the Strings to search for, no-op if null * @param replacementList * the Strings to replace them with, no-op if null * @return the text with any replacements processed, null if * null String input * @throws IndexOutOfBoundsException * if the lengths of the arrays are not the same (null is ok, * and/or size 0) * @since 2.4 */ public static String replaceEach(String text, String[] searchList, String[] replacementList) { return replaceEach(text, searchList, replacementList, false, 0); } /** *

* Replaces all occurrences of Strings within another String. *

* *

* A null reference passed to this method is a no-op, or if * any "search string" or "string to replace" is null, that replace will be * ignored. *

* *
     *  StringUtils.replaceEach(null, *, *, *) = null
     *  StringUtils.replaceEach("", *, *, *) = ""
     *  StringUtils.replaceEach("aba", null, null, *) = "aba"
     *  StringUtils.replaceEach("aba", new String[0], null, *) = "aba"
     *  StringUtils.replaceEach("aba", null, new String[0], *) = "aba"
     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba"
     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b"
     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba"
     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte"
     *  (example of how it repeats)
     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte"
     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte"
     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *) = IllegalArgumentException
     * 
* * @param text * text to search and replace in, no-op if null * @param searchList * the Strings to search for, no-op if null * @param replacementList * the Strings to replace them with, no-op if null * @param repeat if true, then replace repeatedly * until there are no more possible replacements or timeToLive < 0 * @param timeToLive * if less than 0 then there is a circular reference and endless * loop * @return the text with any replacements processed, null if * null String input * @throws IllegalArgumentException * if the search is repeating and there is an endless loop due * to outputs of one being inputs to another * @throws IndexOutOfBoundsException * if the lengths of the arrays are not the same (null is ok, * and/or size 0) * @since 2.4 */ private static String replaceEach(String text, String[] searchList, String[] replacementList, boolean repeat, int timeToLive) { // mchyzer Performance note: This creates very few new objects (one major goal) // let me know if there are performance requests, we can create a harness to measure if (text == null || text.length() == 0 || searchList == null || searchList.length == 0 || replacementList == null || replacementList.length == 0) { return text; } // if recursing, this shouldnt be less than 0 if (timeToLive < 0) { throw new IllegalStateException("TimeToLive of " + timeToLive + " is less than 0: " + text); } int searchLength = searchList.length; int replacementLength = replacementList.length; // make sure lengths are ok, these need to be equal if (searchLength != replacementLength) { throw new IllegalArgumentException("Search and Replace array lengths don't match: " + searchLength + " vs " + replacementLength); } // keep track of which still have matches boolean[] noMoreMatchesForReplIndex = new boolean[searchLength]; // index on index that the match was found int textIndex = -1; int replaceIndex = -1; int tempIndex = -1; // index of replace array that will replace the search string found // NOTE: logic duplicated below START for (int i = 0; i < searchLength; i++) { if (noMoreMatchesForReplIndex[i] || searchList[i] == null || searchList[i].length() == 0 || replacementList[i] == null) { continue; } tempIndex = text.indexOf(searchList[i]); // see if we need to keep searching for this if (tempIndex == -1) { noMoreMatchesForReplIndex[i] = true; } else { if (textIndex == -1 || tempIndex < textIndex) { textIndex = tempIndex; replaceIndex = i; } } } // NOTE: logic mostly below END // no search strings found, we are done if (textIndex == -1) { return text; } int start = 0; // get a good guess on the size of the result buffer so it doesnt have to double if it goes over a bit int increase = 0; // count the replacement text elements that are larger than their corresponding text being replaced for (int i = 0; i < searchList.length; i++) { int greater = replacementList[i].length() - searchList[i].length(); if (greater > 0) { increase += 3 * greater; // assume 3 matches } } // have upper-bound at 20% increase, then let Java take over increase = Math.min(increase, text.length() / 5); StringBuffer buf = new StringBuffer(text.length() + increase); while (textIndex != -1) { for (int i = start; i < textIndex; i++) { buf.append(text.charAt(i)); } buf.append(replacementList[replaceIndex]); start = textIndex + searchList[replaceIndex].length(); textIndex = -1; replaceIndex = -1; tempIndex = -1; // find the next earliest match // NOTE: logic mostly duplicated above START for (int i = 0; i < searchLength; i++) { if (noMoreMatchesForReplIndex[i] || searchList[i] == null || searchList[i].length() == 0 || replacementList[i] == null) { continue; } tempIndex = text.indexOf(searchList[i], start); // see if we need to keep searching for this if (tempIndex == -1) { noMoreMatchesForReplIndex[i] = true; } else { if (textIndex == -1 || tempIndex < textIndex) { textIndex = tempIndex; replaceIndex = i; } } } // NOTE: logic duplicated above END } int textLength = text.length(); for (int i = start; i < textLength; i++) { buf.append(text.charAt(i)); } String result = buf.toString(); if (!repeat) { return result; } return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1); } // Joining //----------------------------------------------------------------------- /** *

Joins the elements of the provided array into a single String * containing the provided list of elements.

* *

No separator is added to the joined String. * Null objects or empty strings within the array are represented by * empty strings.

* *
     * StringUtils.join(null)            = null
     * StringUtils.join([])              = ""
     * StringUtils.join([null])          = ""
     * StringUtils.join(["a", "b", "c"]) = "abc"
     * StringUtils.join([null, "", "a"]) = "a"
     * 
* * @param the specific type of values to join together * @param elements the values to join together, may be null * @return the joined String, {@code null} if null array input * @since 2.0 * @since 3.0 Changed signature to use varargs */ public static String join(T... elements) { return join(elements, null); } /** *

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. * Null objects or empty strings within the array are represented by * empty strings.

* *
     * StringUtils.join(null, *)               = null
     * StringUtils.join([], *)                 = ""
     * StringUtils.join([null], *)             = ""
     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
     * StringUtils.join(["a", "b", "c"], null) = "abc"
     * StringUtils.join([null, "", "a"], ';')  = ";;a"
     * 
* * @param array the array of values to join together, may be null * @param separator the separator character to use * @return the joined String, {@code null} if null array input * @since 2.0 */ public static String join(Object[] array, char separator) { if (array == null) { return null; } return join(array, separator, 0, array.length); } /** *

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. * Null objects or empty strings within the array are represented by * empty strings.

* *
     * StringUtils.join(null, *)               = null
     * StringUtils.join([], *)                 = ""
     * StringUtils.join([null], *)             = ""
     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
     * StringUtils.join(["a", "b", "c"], null) = "abc"
     * StringUtils.join([null, "", "a"], ';')  = ";;a"
     * 
* * @param array the array of values to join together, may be null * @param separator the separator character to use * @param startIndex the first index to start joining from. It is * an error to pass in an end index past the end of the array * @param endIndex the index to stop joining from (exclusive). It is * an error to pass in an end index past the end of the array * @return the joined String, {@code null} if null array input * @since 2.0 */ public static String join(Object[] array, char separator, int startIndex, int endIndex) { if (array == null) { return null; } int noOfItems = (endIndex - startIndex); if (noOfItems <= 0) { return EMPTY; } StringBuilder buf = new StringBuilder(noOfItems * 16); for (int i = startIndex; i < endIndex; i++) { if (i > startIndex) { buf.append(separator); } if (array[i] != null) { buf.append(array[i]); } } return buf.toString(); } /** *

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 {@code null} separator is the same as an empty String (""). * Null objects or empty strings within the array are represented by * empty strings.

* *
     * StringUtils.join(null, *)                = null
     * StringUtils.join([], *)                  = ""
     * StringUtils.join([null], *)              = ""
     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
     * StringUtils.join(["a", "b", "c"], null)  = "abc"
     * StringUtils.join(["a", "b", "c"], "")    = "abc"
     * StringUtils.join([null, "", "a"], ',')   = ",,a"
     * 
* * @param array the array of values to join together, may be null * @param separator the separator character to use, null treated as "" * @return the joined String, {@code null} if null array input */ public static String join(Object[] array, String separator) { if (array == null) { return null; } return join(array, separator, 0, array.length); } /** *

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 {@code null} separator is the same as an empty String (""). * Null objects or empty strings within the array are represented by * empty strings.

* *
     * StringUtils.join(null, *)                = null
     * StringUtils.join([], *)                  = ""
     * StringUtils.join([null], *)              = ""
     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
     * StringUtils.join(["a", "b", "c"], null)  = "abc"
     * StringUtils.join(["a", "b", "c"], "")    = "abc"
     * StringUtils.join([null, "", "a"], ',')   = ",,a"
     * 
* * @param array the array of values to join together, may be null * @param separator the separator character to use, null treated as "" * @param startIndex the first index to start joining from. It is * an error to pass in an end index past the end of the array * @param endIndex the index to stop joining from (exclusive). It is * an error to pass in an end index past the end of the array * @return the joined String, {@code null} if null array input */ public static String join(Object[] array, String separator, int startIndex, int endIndex) { if (array == null) { return null; } if (separator == null) { separator = EMPTY; } // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator)) // (Assuming that all Strings are roughly equally long) int noOfItems = (endIndex - startIndex); if (noOfItems <= 0) { return EMPTY; } StringBuilder buf = new StringBuilder(noOfItems * 16); for (int i = startIndex; i < endIndex; i++) { if (i > startIndex) { buf.append(separator); } if (array[i] != null) { buf.append(array[i]); } } return buf.toString(); } private StringUtils() {} // ------------------------------------------------------------------------- // XXX: The following methods are taken from ObjectUtils // ------------------------------------------------------------------------- /** *

Compares two objects for equality, where either one or both * objects may be {@code null}.

* *
     * ObjectUtils.equals(null, null)                  = true
     * ObjectUtils.equals(null, "")                    = false
     * ObjectUtils.equals("", null)                    = false
     * ObjectUtils.equals("", "")                      = true
     * ObjectUtils.equals(Boolean.TRUE, null)          = false
     * ObjectUtils.equals(Boolean.TRUE, "true")        = false
     * ObjectUtils.equals(Boolean.TRUE, Boolean.TRUE)  = true
     * ObjectUtils.equals(Boolean.TRUE, Boolean.FALSE) = false
     * 
* * @param object1 the first object, may be {@code null} * @param object2 the second object, may be {@code null} * @return {@code true} if the values of both objects are the same */ public static boolean equals(Object object1, Object object2) { if (object1 == object2) { return true; } if ((object1 == null) || (object2 == null)) { return false; } return object1.equals(object2); } /** *

Returns a default value if the object passed is {@code null}.

* *
     * ObjectUtils.defaultIfNull(null, null)      = null
     * ObjectUtils.defaultIfNull(null, "")        = ""
     * ObjectUtils.defaultIfNull(null, "zz")      = "zz"
     * ObjectUtils.defaultIfNull("abc", *)        = "abc"
     * ObjectUtils.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE
     * 
* * @param the type of the object * @param object the {@code Object} to test, may be {@code null} * @param defaultValue the default value to return, may be {@code null} * @return {@code object} if it is not {@code null}, defaultValue otherwise */ public static T defaultIfNull(T object, T defaultValue) { return object != null ? object : defaultValue; } // ------------------------------------------------------------------------- // XXX: The following methods are not part of Apache's commons-lang library // ------------------------------------------------------------------------- /** * Convert a string to camel case */ public static String toCamelCase(String string) { StringBuilder result = new StringBuilder(); // [#2515] - Keep trailing underscores for (String word : string.split("_", -1)) { // Uppercase first letter of a word if (word.length() > 0) { // [#82] - If a word starts with a digit, prevail the // underscore to prevent naming clashes if (Character.isDigit(word.charAt(0))) { result.append("_"); } result.append(word.substring(0, 1).toUpperCase()); result.append(word.substring(1).toLowerCase()); } // If no letter exists, prevail the underscore (e.g. leading // underscores) else { result.append("_"); } } return result.toString(); } /** * Convert a string to camel case starting with a lower case letter */ public static String toCamelCaseLC(String string) { return toLC(toCamelCase(string)); } /** * Change a string's first letter to lower case */ public static String toLC(String string) { if (string == null || string.isEmpty()) { return string; } return Character.toLowerCase(string.charAt(0)) + string.substring(1); } /** * A custom adaptation of {@link Pattern#split(CharSequence, int)}. *

* This is useful if the matched split-tokens should be returned as well. * For example:

     * split("e", "hello world")    // ["h", "e", "llo world"]
     * split("o", "hello world")    // ["hell", "o", " w", "o", "rld"]
     * split("[eo]", "hello world") // ["h", "e", "ll", "o", " w", "o", "rld"]
     * 
*

* The result will always be an odd-length array. */ public static String[] split(String regex, CharSequence input) { int index = 0; ArrayList matchList = new ArrayList(); Matcher m = Pattern.compile(regex).matcher(input); // Add segments before each match found while (m.find()) { matchList.add(input.subSequence(index, m.start()).toString()); matchList.add(input.subSequence(m.start(), m.end()).toString()); index = m.end(); } // If no match was found, return this if (index == 0) return new String[] { input.toString() }; // Add remaining segment matchList.add(input.subSequence(index, input.length()).toString()); // Construct result Iterator it = matchList.iterator(); while (it.hasNext()) { if ("".equals(it.next())) { it.remove(); } } String[] result = new String[matchList.size()]; return matchList.toArray(result); } }