diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/text/CharSequenceUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/text/CharSequenceUtil.java index 9bf3a5fc8..718e76976 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/text/CharSequenceUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/text/CharSequenceUtil.java @@ -1331,7 +1331,7 @@ public class CharSequenceUtil extends StrValidator { final String str2 = str.toString(); int toIndex = str2.length(); - while (str2.startsWith(suffixStr, toIndex - suffixLength)){ + while (str2.startsWith(suffixStr, toIndex - suffixLength)) { toIndex -= suffixLength; } return subPre(str2, toIndex); @@ -1390,6 +1390,11 @@ public class CharSequenceUtil extends StrValidator { /** * 去除两边的指定字符串 + *
{@code + * "aaa_STRIPPED_bbb", "a" -> "aa_STRIPPED_bbb" + * "aaa_STRIPPED_bbb", "" -> "aaa_STRIPPED_bbb" + * } + ** * @param str 被处理的字符串 * @param prefixOrSuffix 前缀或后缀 @@ -1407,6 +1412,18 @@ public class CharSequenceUtil extends StrValidator { /** * 去除两边的指定字符串
{@code + * "aaa_STRIPPED_bbb", "a", "b" -> "aa_STRIPPED_bb" + * "aaa_STRIPPED_bbb", null, null -> "aaa_STRIPPED_bbb" + * "aaa_STRIPPED_bbb", "", "" -> "aaa_STRIPPED_bbb" + * "aaa_STRIPPED_bbb", "", "b" -> "aaa_STRIPPED_bb" + * "aaa_STRIPPED_bbb", null, "b" -> "aaa_STRIPPED_bb" + * "aaa_STRIPPED_bbb", "a", "" -> "aa_STRIPPED_bbb" + * "aaa_STRIPPED_bbb", "a", null -> "aa_STRIPPED_bbb" + * + * "a", "a", "a" -> "" + * } + ** * @param str 被处理的字符串 * @param prefix 前缀 @@ -1419,18 +1436,116 @@ public class CharSequenceUtil extends StrValidator { return toStringOrNull(str); } - int from = 0; - int to = str.length(); - final String str2 = str.toString(); + int from = 0; + int to = str2.length(); + if (startWith(str2, prefix)) { from = prefix.length(); + if(from == to){ + // "a", "a", "a" -> "" + return EMPTY; + } } if (endWith(str2, suffix)) { to -= suffix.length(); + if(from == to){ + // "a", "a", "a" -> "" + return EMPTY; + } else if(to < from){ + // pre去除后和suffix有重叠,如 ("aba", "ab", "ba") -> "a" + to += suffix.length(); + } } - return str2.substring(Math.min(from, to), Math.max(from, to)); + return str2.substring(from, to); + } + + /** + * 去除两边所有的指定字符串 + * + *
{@code + * "aaa_STRIPPED_bbb", "a" -> "_STRIPPED_bbb" + * "aaa_STRIPPED_bbb", "a", "b" -> "_STRIPPED_" + * "aaa_STRIPPED_bbb", "" -> "aaa_STRIPPED_bbb" + * } + *+ * + * @param str 被处理的字符串 + * @param prefixOrSuffix 前缀或后缀 + * @return 处理后的字符串 + * @since 5.8.30 + */ + public static String stripAll(final CharSequence str, final CharSequence prefixOrSuffix) { + if (equals(str, prefixOrSuffix)) { + return EMPTY; + } + return stripAll(str, prefixOrSuffix, prefixOrSuffix); + } + + /** + * 去除两边所有的指定字符串 + * + *
{@code + * "aaa_STRIPPED_bbb", "a", "b" -> "_STRIPPED_" + * "aaa_STRIPPED_bbb", null, null -> "aaa_STRIPPED_bbb" + * "aaa_STRIPPED_bbb", "", "" -> "aaa_STRIPPED_bbb" + * "aaa_STRIPPED_bbb", "", "b" -> "aaa_STRIPPED_" + * "aaa_STRIPPED_bbb", null, "b" -> "aaa_STRIPPED_" + * "aaa_STRIPPED_bbb", "a", "" -> "_STRIPPED_bbb" + * "aaa_STRIPPED_bbb", "a", null -> "_STRIPPED_bbb" + * + * // special test + * "aaaaaabbb", "aaa", null -> "bbb" + * "aaaaaaabbb", "aa", null -> "abbb" + * + * "aaaaaaaaa", "aaa", "aa" -> "" + * "a", "a", "a" -> "" + * } + *+ * + * @param str 被处理的字符串 + * @param prefix 前缀 + * @param suffix 后缀 + * @return 处理后的字符串 + * @since 5.8.30 + */ + public static String stripAll(final CharSequence str, final CharSequence prefix, final CharSequence suffix) { + if (isEmpty(str)) { + return toStringOrNull(str); + } + + final String prefixStr = toStringOrEmpty(prefix); + final String suffixStr = toStringOrEmpty(suffix); + + final String str2 = str.toString(); + int from = 0; + int to = str2.length(); + + if(!prefixStr.isEmpty()){ + while (str2.startsWith(prefixStr, from)) { + from += prefix.length(); + if(from == to){ + // "a", "a", "a" -> "" + return EMPTY; + } + } + } + if(!suffixStr.isEmpty()){ + while (str2.startsWith(suffixStr, to - suffixStr.length())) { + to -= suffixStr.length(); + if(from == to){ + // "a", "a", "a" -> "" + return EMPTY; + }else if(to < from){ + // pre去除后和suffix有重叠,如 ("aba", "ab", "ba") -> "a" + to += suffixStr.length(); + break; + } + } + } + + return str2.substring(from, to); } /** diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/text/CharSequenceUtilTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/text/CharSequenceUtilTest.java index 6315f774f..35e2172e3 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/text/CharSequenceUtilTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/text/CharSequenceUtilTest.java @@ -450,4 +450,63 @@ public class CharSequenceUtilTest { result = CharSequenceUtil.removeAllSuffix(str, prefix); assertNull(result); } + + @Test + public void stripTest() { + + final String SOURCE_STRING = "aaa_STRIPPED_bbb"; + + // ---------------------------- test strip ---------------------------- + + // Normal test + assertEquals("aa_STRIPPED_bbb", CharSequenceUtil.strip(SOURCE_STRING, "a")); + assertEquals(SOURCE_STRING, CharSequenceUtil.strip(SOURCE_STRING, "")); + assertEquals("aa_STRIPPED_bb", CharSequenceUtil.strip(SOURCE_STRING, "a", "b")); + + // test null param + assertEquals(SOURCE_STRING, CharSequenceUtil.strip(SOURCE_STRING, null, null)); + assertEquals(SOURCE_STRING, CharSequenceUtil.strip(SOURCE_STRING, "", "")); + assertEquals("aaa_STRIPPED_bb", CharSequenceUtil.strip(SOURCE_STRING, "", "b")); + assertEquals("aaa_STRIPPED_bb", CharSequenceUtil.strip(SOURCE_STRING, null, "b")); + assertEquals("aa_STRIPPED_bbb", CharSequenceUtil.strip(SOURCE_STRING, "a", "")); + assertEquals("aa_STRIPPED_bbb", CharSequenceUtil.strip(SOURCE_STRING, "a", null)); + // 本次提交前无法通过的 case + assertEquals("", CharSequenceUtil.strip("a", "a", "a")); + + // 前缀后缀有重叠,优先去掉前缀 + assertEquals("a", CharSequenceUtil.strip("aba", "ab", "ba")); + } + + @Test + void stripAllTest() { + final String SOURCE_STRING = "aaa_STRIPPED_bbb"; + + // ---------------------------- test stripAll ---------------------------- + + // Normal test + assertEquals("_STRIPPED_bbb", CharSequenceUtil.stripAll(SOURCE_STRING, "a")); + assertEquals(SOURCE_STRING, CharSequenceUtil.stripAll(SOURCE_STRING, "")); + + // test null param + assertEquals("_STRIPPED_", CharSequenceUtil.stripAll(SOURCE_STRING, "a", "b")); + assertEquals(SOURCE_STRING, CharSequenceUtil.stripAll(SOURCE_STRING, null, null)); + assertEquals(SOURCE_STRING, CharSequenceUtil.stripAll(SOURCE_STRING, "", "")); + assertEquals("aaa_STRIPPED_", CharSequenceUtil.stripAll(SOURCE_STRING, "", "b")); + assertEquals("aaa_STRIPPED_", CharSequenceUtil.stripAll(SOURCE_STRING, null, "b")); + assertEquals("_STRIPPED_bbb", CharSequenceUtil.stripAll(SOURCE_STRING, "a", "")); + assertEquals("_STRIPPED_bbb", CharSequenceUtil.stripAll(SOURCE_STRING, "a", null)); + + // special test + assertEquals("bbb", CharSequenceUtil.stripAll("aaaaaabbb", "aaa", null)); + assertEquals("abbb", CharSequenceUtil.stripAll("aaaaaaabbb", "aa", null)); + + // aaaaaaaaa (9个a) 可以被看为 aaa_aaaa_aa + assertEquals("", CharSequenceUtil.stripAll("aaaaaaaaa", "aaa", "aa")); + // 第二次迭代后会出现 from 比 to 大的情况,原本代码是强行交换,但是回导致无法去除前后缀 + assertEquals("", CharSequenceUtil.stripAll("a", "a", "a")); + + // 前缀后缀有重叠,优先去掉前缀 + assertEquals("a", CharSequenceUtil.stripAll("aba", "ab", "ba")); + assertEquals("a", CharSequenceUtil.stripAll("abababa", "ab", "ba")); + } }