From 3a7b485734185c8ecdfaa14dbeb46c711008083f Mon Sep 17 00:00:00 2001 From: Laurent SCHOELENS Date: Tue, 14 Mar 2023 11:33:27 +0100 Subject: [PATCH 1/2] LANG-1687 : Propose update from substringBetween doc and new method --- .../org/apache/commons/lang3/StringUtils.java | 46 ++++++++++++++++++- .../lang3/StringUtilsSubstringTest.java | 32 +++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) 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..b65f60c71ff 100644 --- a/src/test/java/org/apache/commons/lang3/StringUtilsSubstringTest.java +++ b/src/test/java/org/apache/commons/lang3/StringUtilsSubstringTest.java @@ -288,6 +288,38 @@ public void testSubstringBetween_StringStringString() { assertEquals("bar", StringUtils.substringBetween("bar", "", "") ); 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. From b74a7cfe7187d900064003978bc6fa82dcbfb73e Mon Sep 17 00:00:00 2001 From: Laurent SCHOELENS Date: Tue, 14 Mar 2023 14:08:44 +0100 Subject: [PATCH 2/2] fix checkstyle violations --- .../commons/lang3/StringUtilsSubstringTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/java/org/apache/commons/lang3/StringUtilsSubstringTest.java b/src/test/java/org/apache/commons/lang3/StringUtilsSubstringTest.java index b65f60c71ff..1baa283b35e 100644 --- a/src/test/java/org/apache/commons/lang3/StringUtilsSubstringTest.java +++ b/src/test/java/org/apache/commons/lang3/StringUtilsSubstringTest.java @@ -288,7 +288,7 @@ public void testSubstringBetween_StringStringString() { assertEquals("bar", StringUtils.substringBetween("bar", "", "") ); assertEquals("abc", StringUtils.substringBetween("yabczyabcz", "y", "z")); } - + @Test public void testSubstringBetween_StringStringStringBoolean() { // same tests as testSubstringBetween_StringStringString with true parameter @@ -296,24 +296,24 @@ public void testSubstringBetween_StringStringStringBoolean() { 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));