diff --git a/src/changes/changes.xml b/src/changes/changes.xml index bc720f759..a9b58e203 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -46,6 +46,7 @@ The type attribute can be add,update,fix,remove. + Add method removeIgnoreCase(String, String) to StringUtils ArrayUtils.contains returns false for instances of subtypes Prepare Java 9 detection Rename NumberUtils.isNumber, isCreatable to better reflect createNumber. Also, accommodated for "+" symbol as prefix in isCreatable and isNumber. diff --git a/src/main/java/org/apache/commons/lang3/StringUtils.java b/src/main/java/org/apache/commons/lang3/StringUtils.java index 02c7106a4..879139423 100644 --- a/src/main/java/org/apache/commons/lang3/StringUtils.java +++ b/src/main/java/org/apache/commons/lang3/StringUtils.java @@ -4819,6 +4819,46 @@ public class StringUtils { return replace(str, remove, EMPTY, -1); } + /** + *

+ * Case insensitive removal of all occurrences of a substring from within + * the source string. + *

+ * + *

+ * A {@code null} source string will return {@code null}. An empty ("") + * source string will return the empty string. A {@code null} remove string + * will return the source string. An empty ("") remove string will return + * the source string. + *

+ * + *
+     * StringUtils.removeIgnoreCase(null, *)        = null
+     * StringUtils.removeIgnoreCase("", *)          = ""
+     * StringUtils.removeIgnoreCase(*, null)        = *
+     * StringUtils.removeIgnoreCase(*, "")          = *
+     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
+     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
+     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
+     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
+     * 
+ * + * @param str + * the source String to search, may be null + * @param remove + * the String to search for (case insensitive) and remove, may be + * null + * @return the substring with the string removed if found, {@code null} if + * null String input + * @since 3.5 + */ + public static String removeIgnoreCase(String str, String remove) { + if (isEmpty(str) || isEmpty(remove)) { + return str; + } + return replaceIgnoreCase(str, remove, EMPTY, -1); + } + /** *

Removes all occurrences of a character from within the source string.

* @@ -4974,6 +5014,35 @@ public class StringUtils { return replace(text, searchString, replacement, 1); } + /** + *

Case insensitively replaces a String with another String inside a larger String, once.

+ * + *

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

+ * + *
+     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
+     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
+     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
+     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
+     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
+     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
+     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
+     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
+     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
+     * 
+ * + * @see #replaceIgnoreCase(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 (case insensitive), may be null + * @param replacement the String to replace with, may be null + * @return the text with any replacements processed, + * {@code null} if null String input + * @since 3.5 + */ + public static String replaceOnceIgnoreCase(String text, String searchString, String replacement) { + return replaceIgnoreCase(text, searchString, replacement, 1); + } + /** *

Replaces each substring of the source String that matches the given regular expression with the given * replacement using the {@link Pattern#DOTALL} option. DOTALL is also know as single-line mode in Perl.

@@ -5189,6 +5258,34 @@ public class StringUtils { return replace(text, searchString, replacement, -1); } + /** + *

Case insensitively replaces all occurrences of a String within another String.

+ * + *

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

+ * + *
+    * StringUtils.replaceIgnoreCase(null, *, *)        = null
+    * StringUtils.replaceIgnoreCase("", *, *)          = ""
+    * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
+    * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
+    * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
+    * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
+    * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
+    * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
+    * 
+ * + * @see #replaceIgnoreCase(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 (case insensitive), 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 + * @since 3.5 + */ + public static String replaceIgnoreCase(String text, String searchString, String replacement) { + return replaceIgnoreCase(text, searchString, replacement, -1); + } + /** *

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

@@ -5218,29 +5315,102 @@ public class StringUtils { * {@code null} if null String input */ public static String replace(final String text, final String searchString, final 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; - } - final int replLength = searchString.length(); - int increase = replacement.length() - replLength; - increase = increase < 0 ? 0 : increase; - increase *= max < 0 ? 16 : max > 64 ? 64 : max; - final 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(); + return replace(text, searchString, replacement, max, false); + } + + /** + *

Replaces a String with another String inside a larger String, + * for the first {@code max} values of the search String, + * case sensitively/insensisitively based on {@code ignoreCase} value.

+ * + *

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

+ * + *
+     * StringUtils.replace(null, *, *, *, false)         = null
+     * StringUtils.replace("", *, *, *, false)           = ""
+     * StringUtils.replace("any", null, *, *, false)     = "any"
+     * StringUtils.replace("any", *, null, *, false)     = "any"
+     * StringUtils.replace("any", "", *, *, false)       = "any"
+     * StringUtils.replace("any", *, *, 0, false)        = "any"
+     * StringUtils.replace("abaa", "a", null, -1, false) = "abaa"
+     * StringUtils.replace("abaa", "a", "", -1, false)   = "b"
+     * StringUtils.replace("abaa", "a", "z", 0, false)   = "abaa"
+     * StringUtils.replace("abaa", "A", "z", 1, false)   = "abaa"
+     * StringUtils.replace("abaa", "A", "z", 1, true)   = "zbaa"
+     * StringUtils.replace("abAa", "a", "z", 2, true)   = "zbza"
+     * StringUtils.replace("abAa", "a", "z", -1, true)  = "zbzz"
+     * 
+ * + * @param text text to search and replace in, may be null + * @param searchString the String to search for (case insensitive), 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 + * @param ignoreCase if true replace is case insensitive, otherwise case sensitive + * @return the text with any replacements processed, + * {@code null} if null String input + */ + private static String replace(String text, String searchString, String replacement, int max, boolean ignoreCase) { + if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) { + return text; + } + String searchText = text; + if (ignoreCase) { + searchText = text.toLowerCase(); + searchString = searchString.toLowerCase(); + } + int start = 0; + int end = searchText.indexOf(searchString, start); + if (end == INDEX_NOT_FOUND) { + return text; + } + final int replLength = searchString.length(); + int increase = replacement.length() - replLength; + increase = increase < 0 ? 0 : increase; + increase *= max < 0 ? 16 : max > 64 ? 64 : max; + final 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 = searchText.indexOf(searchString, start); + } + buf.append(text.substring(start)); + return buf.toString(); + } + + /** + *

Case insensitively 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.replaceIgnoreCase(null, *, *, *)         = null
+     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
+     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
+     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
+     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
+     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
+     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
+     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
+     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
+     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
+     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
+     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
+     * 
+ * + * @param text text to search and replace in, may be null + * @param searchString the String to search for (case insensitive), 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 + * @since 3.5 + */ + public static String replaceIgnoreCase(String text, String searchString, String replacement, int max) { + return replace(text, searchString, replacement, max, true); } /** diff --git a/src/test/java/org/apache/commons/lang3/StringUtilsTest.java b/src/test/java/org/apache/commons/lang3/StringUtilsTest.java index 75cfa383e..8f0e88e4a 100644 --- a/src/test/java/org/apache/commons/lang3/StringUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/StringUtilsTest.java @@ -1122,6 +1122,33 @@ public class StringUtilsTest { assertEquals("farfarfar", StringUtils.replace("foofoofoo", "oo", "ar")); } + @Test + public void testReplaceIgnoreCase_StringStringString() { + assertEquals(null, StringUtils.replaceIgnoreCase(null, null, null)); + assertEquals(null, StringUtils.replaceIgnoreCase(null, null, "any")); + assertEquals(null, StringUtils.replaceIgnoreCase(null, "any", null)); + assertEquals(null, StringUtils.replaceIgnoreCase(null, "any", "any")); + + assertEquals("", StringUtils.replaceIgnoreCase("", null, null)); + assertEquals("", StringUtils.replaceIgnoreCase("", null, "any")); + assertEquals("", StringUtils.replaceIgnoreCase("", "any", null)); + assertEquals("", StringUtils.replaceIgnoreCase("", "any", "any")); + + assertEquals("FOO", StringUtils.replaceIgnoreCase("FOO", "", "any")); + assertEquals("FOO", StringUtils.replaceIgnoreCase("FOO", null, "any")); + assertEquals("FOO", StringUtils.replaceIgnoreCase("FOO", "F", null)); + assertEquals("FOO", StringUtils.replaceIgnoreCase("FOO", null, null)); + + assertEquals("", StringUtils.replaceIgnoreCase("foofoofoo", "foo", "")); + assertEquals("barbarbar", StringUtils.replaceIgnoreCase("foofoofoo", "foo", "bar")); + assertEquals("farfarfar", StringUtils.replaceIgnoreCase("foofoofoo", "oo", "ar")); + + // IgnoreCase + assertEquals("", StringUtils.replaceIgnoreCase("foofoofoo", "FOO", "")); + assertEquals("barbarbar", StringUtils.replaceIgnoreCase("fooFOOfoo", "foo", "bar")); + assertEquals("farfarfar", StringUtils.replaceIgnoreCase("foofOOfoo", "OO", "ar")); + } + @Test public void testReplacePattern() { assertNull(StringUtils.replacePattern(null, "", "")); @@ -1244,6 +1271,43 @@ public class StringUtilsTest { assertEquals("f", StringUtils.replace("oofoo", "o", "", 1000)); } + @Test + public void testReplaceIgnoreCase_StringStringStringInt() { + assertEquals(null, StringUtils.replaceIgnoreCase(null, null, null, 2)); + assertEquals(null, StringUtils.replaceIgnoreCase(null, null, "any", 2)); + assertEquals(null, StringUtils.replaceIgnoreCase(null, "any", null, 2)); + assertEquals(null, StringUtils.replaceIgnoreCase(null, "any", "any", 2)); + + assertEquals("", StringUtils.replaceIgnoreCase("", null, null, 2)); + assertEquals("", StringUtils.replaceIgnoreCase("", null, "any", 2)); + assertEquals("", StringUtils.replaceIgnoreCase("", "any", null, 2)); + assertEquals("", StringUtils.replaceIgnoreCase("", "any", "any", 2)); + + String str = new String(new char[] { 'o', 'o', 'f', 'o', 'o' }); + assertSame(str, StringUtils.replaceIgnoreCase(str, "x", "", -1)); + + assertEquals("f", StringUtils.replaceIgnoreCase("oofoo", "o", "", -1)); + assertEquals("oofoo", StringUtils.replaceIgnoreCase("oofoo", "o", "", 0)); + assertEquals("ofoo", StringUtils.replaceIgnoreCase("oofoo", "o", "", 1)); + assertEquals("foo", StringUtils.replaceIgnoreCase("oofoo", "o", "", 2)); + assertEquals("fo", StringUtils.replaceIgnoreCase("oofoo", "o", "", 3)); + assertEquals("f", StringUtils.replaceIgnoreCase("oofoo", "o", "", 4)); + + assertEquals("f", StringUtils.replaceIgnoreCase("oofoo", "o", "", -5)); + assertEquals("f", StringUtils.replaceIgnoreCase("oofoo", "o", "", 1000)); + + // IgnoreCase + assertEquals("f", StringUtils.replaceIgnoreCase("oofoo", "O", "", -1)); + assertEquals("oofoo", StringUtils.replaceIgnoreCase("oofoo", "O", "", 0)); + assertEquals("ofoo", StringUtils.replaceIgnoreCase("oofoo", "O", "", 1)); + assertEquals("foo", StringUtils.replaceIgnoreCase("oofoo", "O", "", 2)); + assertEquals("fo", StringUtils.replaceIgnoreCase("oofoo", "O", "", 3)); + assertEquals("f", StringUtils.replaceIgnoreCase("oofoo", "O", "", 4)); + + assertEquals("f", StringUtils.replaceIgnoreCase("oofoo", "O", "", -5)); + assertEquals("f", StringUtils.replaceIgnoreCase("oofoo", "O", "", 1000)); + } + @Test public void testReplaceOnce_StringStringString() { assertNull(StringUtils.replaceOnce(null, null, null)); @@ -1264,6 +1328,29 @@ public class StringUtilsTest { assertEquals("foofoo", StringUtils.replaceOnce("foofoofoo", "foo", "")); } + @Test + public void testReplaceOnceIgnoreCase_StringStringString() { + assertEquals(null, StringUtils.replaceOnceIgnoreCase(null, null, null)); + assertEquals(null, StringUtils.replaceOnceIgnoreCase(null, null, "any")); + assertEquals(null, StringUtils.replaceOnceIgnoreCase(null, "any", null)); + assertEquals(null, StringUtils.replaceOnceIgnoreCase(null, "any", "any")); + + assertEquals("", StringUtils.replaceOnceIgnoreCase("", null, null)); + assertEquals("", StringUtils.replaceOnceIgnoreCase("", null, "any")); + assertEquals("", StringUtils.replaceOnceIgnoreCase("", "any", null)); + assertEquals("", StringUtils.replaceOnceIgnoreCase("", "any", "any")); + + assertEquals("FOO", StringUtils.replaceOnceIgnoreCase("FOO", "", "any")); + assertEquals("FOO", StringUtils.replaceOnceIgnoreCase("FOO", null, "any")); + assertEquals("FOO", StringUtils.replaceOnceIgnoreCase("FOO", "F", null)); + assertEquals("FOO", StringUtils.replaceOnceIgnoreCase("FOO", null, null)); + + assertEquals("foofoo", StringUtils.replaceOnceIgnoreCase("foofoofoo", "foo", "")); + + // Ignore Case + assertEquals("Foofoo", StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "")); + } + /** * Test method for 'StringUtils.replaceEach(String, String[], String[])' */ @@ -2485,6 +2572,42 @@ public class StringUtilsTest { assertEquals("queued", StringUtils.remove("queued", "zz")); } + @Test + public void testRemoveIgnoreCase_String() { + // StringUtils.removeIgnoreCase(null, *) = null + assertEquals(null, StringUtils.removeIgnoreCase(null, null)); + assertEquals(null, StringUtils.removeIgnoreCase(null, "")); + assertEquals(null, StringUtils.removeIgnoreCase(null, "a")); + + // StringUtils.removeIgnoreCase("", *) = "" + assertEquals("", StringUtils.removeIgnoreCase("", null)); + assertEquals("", StringUtils.removeIgnoreCase("", "")); + assertEquals("", StringUtils.removeIgnoreCase("", "a")); + + // StringUtils.removeIgnoreCase(*, null) = * + assertEquals(null, StringUtils.removeIgnoreCase(null, null)); + assertEquals("", StringUtils.removeIgnoreCase("", null)); + assertEquals("a", StringUtils.removeIgnoreCase("a", null)); + + // StringUtils.removeIgnoreCase(*, "") = * + assertEquals(null, StringUtils.removeIgnoreCase(null, "")); + assertEquals("", StringUtils.removeIgnoreCase("", "")); + assertEquals("a", StringUtils.removeIgnoreCase("a", "")); + + // StringUtils.removeIgnoreCase("queued", "ue") = "qd" + assertEquals("qd", StringUtils.removeIgnoreCase("queued", "ue")); + + // StringUtils.removeIgnoreCase("queued", "zz") = "queued" + assertEquals("queued", StringUtils.removeIgnoreCase("queued", "zz")); + + // IgnoreCase + // StringUtils.removeIgnoreCase("quEUed", "UE") = "qd" + assertEquals("qd", StringUtils.removeIgnoreCase("quEUed", "UE")); + + // StringUtils.removeIgnoreCase("queued", "zZ") = "queued" + assertEquals("queued", StringUtils.removeIgnoreCase("queued", "zZ")); + } + @Test public void testRemove_char() { // StringUtils.remove(null, *) = null