diff --git a/src/main/java/org/apache/commons/lang3/StringUtils.java b/src/main/java/org/apache/commons/lang3/StringUtils.java index 9f2b18f5004..24b8face4a4 100644 --- a/src/main/java/org/apache/commons/lang3/StringUtils.java +++ b/src/main/java/org/apache/commons/lang3/StringUtils.java @@ -8778,17 +8778,59 @@ public static String substringBetween(final String str, final String tag) { * * @param str the String containing the substring, may be null * @param open the String before the substring, may be null - * @param close the String after the substring, may be null + * @param close the String after the substring, may be null - search first match from left to right, after the open String found * @return the substring, {@code null} if no match * @since 2.0 */ public static String substringBetween(final String str, final String open, final String close) { + return substringBetween(str, open, close, false); + } + /** + * Gets the String that is nested in between two Strings. + * Only the first match is returned. + * + *

A {@code null} input String returns {@code null}. + * A {@code null} open/close returns {@code null} (no match). + * An empty ("") open and close returns an empty string.

+ * + *
+     * StringUtils.substringBetween("wx[b]yz", "[", "]", *)          = "b"
+     * StringUtils.substringBetween(null, *, *, *)                   = null
+     * StringUtils.substringBetween(*, null, *, *)                   = null
+     * StringUtils.substringBetween(*, *, null, *)                   = null
+     * StringUtils.substringBetween("", "", "", *)                   = ""
+     * StringUtils.substringBetween("", "", "]", *)                  = null
+     * StringUtils.substringBetween("", "[", "]", *)                 = null
+     * StringUtils.substringBetween("yabcz", "", "", false)          = ""
+     * StringUtils.substringBetween("yabcz", "", "", true)           = "yabcz"
+     * StringUtils.substringBetween("yabcz", "y", "z", *)            = "abc"
+     * StringUtils.substringBetween("yabczyabcz", "y", "z", false)   = "abc"
+     * StringUtils.substringBetween("yabczyabcz", "y", "z", true)    = "abczyabc"
+     * StringUtils.substringBetween("zabcyabc", "y", "z", *)         = null
+     * 
+ * + * @param str the String containing the substring, may be null + * @param open the String before the substring, may be null + * @param close the String after the substring, may be null + * @param lastClose set to true if close String must be searched from the end of the String str + * @return the substring, {@code null} if no match + * @since 3.13 + */ + public static String substringBetween(final String str, final String open, final String close, final boolean lastClose) { if (!ObjectUtils.allNotNull(str, open, close)) { return null; } final int start = str.indexOf(open); if (start != INDEX_NOT_FOUND) { - final int end = str.indexOf(close, start + open.length()); + int end = INDEX_NOT_FOUND; + if (!lastClose) { + end = str.indexOf(close, start + open.length()); + } else { + end = str.lastIndexOf(close); + if (end < start + open.length()) { + end = INDEX_NOT_FOUND; + } + } if (end != INDEX_NOT_FOUND) { return str.substring(start + open.length(), end); } diff --git a/src/test/java/org/apache/commons/lang3/StringUtilsSubstringTest.java b/src/test/java/org/apache/commons/lang3/StringUtilsSubstringTest.java index a6f6bf5d076..1baa283b35e 100644 --- a/src/test/java/org/apache/commons/lang3/StringUtilsSubstringTest.java +++ b/src/test/java/org/apache/commons/lang3/StringUtilsSubstringTest.java @@ -289,6 +289,38 @@ public void testSubstringBetween_StringStringString() { assertEquals("abc", StringUtils.substringBetween("yabczyabcz", "y", "z")); } + @Test + public void testSubstringBetween_StringStringStringBoolean() { + // same tests as testSubstringBetween_StringStringString with true parameter + assertNull(StringUtils.substringBetween(null, "", "", true)); + assertNull(StringUtils.substringBetween("", null, "", true)); + assertNull(StringUtils.substringBetween("", "", null, true)); + assertEquals("", StringUtils.substringBetween("", "", "", true)); + + // not same behaviour for boolean param + assertEquals("", StringUtils.substringBetween("foo", "", "", false)); + assertEquals("foo", StringUtils.substringBetween("foo", "", "", true)); + + assertNull(StringUtils.substringBetween("foo", "", "]", true)); + assertNull(StringUtils.substringBetween("foo", "[", "]", true)); + + assertEquals(" ", StringUtils.substringBetween(" ", " ", " ", true)); + assertEquals("bar", StringUtils.substringBetween("bar", "", "", true) ); + + // testing javadoc examples + assertEquals("b", StringUtils.substringBetween("wx[b]yz", "[", "]", false) ); + assertEquals("b", StringUtils.substringBetween("wx[b]yz", "[", "]", true) ); + + assertEquals("abc", StringUtils.substringBetween("yabcz", "y", "z", false) ); + assertEquals("abc", StringUtils.substringBetween("yabcz", "y", "z", true) ); + + assertEquals("abc", StringUtils.substringBetween("yabczyabcz", "y", "z", false)); + assertEquals("abczyabc", StringUtils.substringBetween("yabczyabcz", "y", "z", true)); + + assertNull(StringUtils.substringBetween("zabcyabc", "y", "z", false)); + assertNull(StringUtils.substringBetween("zabcyabc", "y", "z", true)); + } + /** * Tests the substringsBetween method that returns a String Array of substrings. */