From 197e89e6924c3494535344d5247368a80e3cda41 Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 7 Mar 2024 16:03:57 +0800 Subject: [PATCH] fix code --- .../hutool/core/text/CharSequenceUtil.java | 12 ++++----- .../text/replacer/RangeReplacerByChar.java | 27 +++++++++++++++---- .../text/replacer/RangeReplacerByStr.java | 27 +++++++++++++++---- .../core/text/CharSequenceUtilTest.java | 4 +-- .../hutool/core/text/IssueI96LWHTest.java | 16 +++++++++++ .../dromara/hutool/core/text/StrUtilTest.java | 14 +++++----- 6 files changed, 75 insertions(+), 25 deletions(-) create mode 100644 hutool-core/src/test/java/org/dromara/hutool/core/text/IssueI96LWHTest.java 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 b47003ae9..7419928bc 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 @@ -2908,7 +2908,7 @@ public class CharSequenceUtil extends StrValidator { if (INDEX_NOT_FOUND == startInclude) { return str(str); } - return replace(str, startInclude, startInclude + searchStr.length(), replacedStr); + return replaceByCodePoint(str, startInclude, startInclude + searchStr.length(), replacedStr); } /** @@ -3002,8 +3002,8 @@ public class CharSequenceUtil extends StrValidator { * @return 替换后的字符串 * @since 3.2.1 */ - public static String replace(final CharSequence str, final int beginInclude, final int endExclude, final char replacedChar) { - return new RangeReplacerByChar(beginInclude, endExclude, replacedChar).apply(str); + public static String replaceByCodePoint(final CharSequence str, final int beginInclude, final int endExclude, final char replacedChar) { + return new RangeReplacerByChar(beginInclude, endExclude, replacedChar, true).apply(str); } /** @@ -3017,8 +3017,8 @@ public class CharSequenceUtil extends StrValidator { * @return 替换后的字符串 * @since 3.2.1 */ - public static String replace(final CharSequence str, final int beginInclude, final int endExclude, final CharSequence replacedStr) { - return new RangeReplacerByStr(beginInclude, endExclude, replacedStr).apply(str); + public static String replaceByCodePoint(final CharSequence str, final int beginInclude, final int endExclude, final CharSequence replacedStr) { + return new RangeReplacerByStr(beginInclude, endExclude, replacedStr, true).apply(str); } /** @@ -3075,7 +3075,7 @@ public class CharSequenceUtil extends StrValidator { * @since 4.1.14 */ public static String hide(final CharSequence str, final int startInclude, final int endExclude) { - return replace(str, startInclude, endExclude, '*'); + return replaceByCodePoint(str, startInclude, endExclude, '*'); } /** diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/text/replacer/RangeReplacerByChar.java b/hutool-core/src/main/java/org/dromara/hutool/core/text/replacer/RangeReplacerByChar.java index a7beafbe8..368013def 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/text/replacer/RangeReplacerByChar.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/text/replacer/RangeReplacerByChar.java @@ -26,18 +26,21 @@ public class RangeReplacerByChar extends StrReplacer { private final int beginInclude; private final int endExclude; private final char replacedChar; + private final boolean isCodePoint; /** * 构造 * * @param beginInclude 开始位置(包含) * @param endExclude 结束位置(不包含) - * @param replacedChar 被替换的字符串 + * @param replacedChar 被替换的字符串 + * @param isCodePoint 是否code point模式,此模式下emoji等会被作为单独的字符 */ - public RangeReplacerByChar(final int beginInclude, final int endExclude, final char replacedChar) { + public RangeReplacerByChar(final int beginInclude, final int endExclude, final char replacedChar, final boolean isCodePoint) { this.beginInclude = beginInclude; this.endExclude = endExclude; this.replacedChar = replacedChar; + this.isCodePoint = isCodePoint; } @Override @@ -47,8 +50,8 @@ public class RangeReplacerByChar extends StrReplacer { } final String originalStr = StrUtil.str(str); - final int[] strCodePoints = originalStr.codePoints().toArray(); - final int strLength = strCodePoints.length; + final int[] chars = (isCodePoint ? originalStr.codePoints() : originalStr.chars()).toArray(); + final int strLength = chars.length; final int beginInclude = this.beginInclude; if (beginInclude > strLength) { @@ -71,7 +74,7 @@ public class RangeReplacerByChar extends StrReplacer { replace(originalStr, i, stringBuilder); } else { // 其它字符保留 - stringBuilder.appendCodePoint(strCodePoints[i]); + append(stringBuilder, chars[i]); } } return stringBuilder.toString(); @@ -82,4 +85,18 @@ public class RangeReplacerByChar extends StrReplacer { out.appendCodePoint(replacedChar); return pos; } + + /** + * 追加字符 + * + * @param stringBuilder {@link StringBuilder} + * @param c 字符 + */ + private void append(final StringBuilder stringBuilder, final int c) { + if (isCodePoint) { + stringBuilder.appendCodePoint(c); + } else { + stringBuilder.append((char) c); + } + } } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/text/replacer/RangeReplacerByStr.java b/hutool-core/src/main/java/org/dromara/hutool/core/text/replacer/RangeReplacerByStr.java index dc2893a32..8f35afc48 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/text/replacer/RangeReplacerByStr.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/text/replacer/RangeReplacerByStr.java @@ -26,6 +26,7 @@ public class RangeReplacerByStr extends StrReplacer { private final int beginInclude; private final int endExclude; private final CharSequence replacedStr; + private final boolean isCodePoint; /** * 构造 @@ -33,11 +34,13 @@ public class RangeReplacerByStr extends StrReplacer { * @param beginInclude 开始位置(包含) * @param endExclude 结束位置(不包含) * @param replacedStr 被替换的字符串 + * @param isCodePoint 是否code point模式,此模式下emoji等会被作为单独的字符 */ - public RangeReplacerByStr(final int beginInclude, final int endExclude, final CharSequence replacedStr) { + public RangeReplacerByStr(final int beginInclude, final int endExclude, final CharSequence replacedStr, final boolean isCodePoint) { this.beginInclude = beginInclude; this.endExclude = endExclude; this.replacedStr = replacedStr; + this.isCodePoint = isCodePoint; } @Override @@ -47,8 +50,8 @@ public class RangeReplacerByStr extends StrReplacer { } final String originalStr = StrUtil.str(str); - final int[] strCodePoints = originalStr.codePoints().toArray(); - final int strLength = strCodePoints.length; + final int[] chars = (isCodePoint ? originalStr.codePoints() : originalStr.chars()).toArray(); + final int strLength = chars.length; final int beginInclude = this.beginInclude; if (beginInclude > strLength) { @@ -66,11 +69,11 @@ public class RangeReplacerByStr extends StrReplacer { // 新字符串长度 <= 旧长度 - (被替换区间codePoints数量) + 替换字符串长度 final StringBuilder stringBuilder = new StringBuilder(originalStr.length() - (endExclude - beginInclude) + replacedStr.length()); for (int i = 0; i < beginInclude; i++) { - stringBuilder.appendCodePoint(strCodePoints[i]); + append(stringBuilder, chars[i]); } replace(originalStr, beginInclude, stringBuilder); for (int i = endExclude; i < strLength; i++) { - stringBuilder.appendCodePoint(strCodePoints[i]); + append(stringBuilder, chars[i]); } return stringBuilder.toString(); } @@ -83,4 +86,18 @@ public class RangeReplacerByStr extends StrReplacer { // 无意义的返回 return endExclude; } + + /** + * 追加字符 + * + * @param stringBuilder {@link StringBuilder} + * @param c 字符 + */ + private void append(final StringBuilder stringBuilder, final int c) { + if (isCodePoint) { + stringBuilder.appendCodePoint(c); + } else { + stringBuilder.append((char) c); + } + } } 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 b5efdc0df..9cb8ca7e7 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 @@ -40,10 +40,10 @@ public class CharSequenceUtilTest { @Test public void replaceByStrTest() { final String replace = "SSM15930297701BeryAllen"; - final String result = CharSequenceUtil.replace(replace, 5, 12, "***"); + final String result = CharSequenceUtil.replaceByCodePoint(replace, 5, 12, "***"); Assertions.assertEquals("SSM15***01BeryAllen", result); - final String emoji = StrUtil.replace("\uD83D\uDE00aabb\uD83D\uDE00ccdd", 2, 6, "***"); + final String emoji = StrUtil.replaceByCodePoint("\uD83D\uDE00aabb\uD83D\uDE00ccdd", 2, 6, "***"); Assertions.assertEquals("\uD83D\uDE00a***ccdd", emoji); } diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/text/IssueI96LWHTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/text/IssueI96LWHTest.java new file mode 100644 index 000000000..72f37fec9 --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/text/IssueI96LWHTest.java @@ -0,0 +1,16 @@ +package org.dromara.hutool.core.text; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class IssueI96LWHTest { + + @Test + public void replaceByCodePointTest() { + final String str = "\uD83D\uDC46最上方点击蓝字"; + + // 这个方法里\uD83D\uDC46表示一个emoji表情,使用codePoint之后,一个表情表示一个字符,因此按照一个字符对 + Assertions.assertEquals("\uD83D\uDC46最上下点击蓝字", StrUtil.replaceByCodePoint(str, 3, 4, "下")); + Assertions.assertEquals("\uD83D\uDC46最下方点击蓝字", new StringBuilder(str).replace(3, 4, "下").toString()); + } +} diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/text/StrUtilTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/text/StrUtilTest.java index c26988188..be7058d8b 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/text/StrUtilTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/text/StrUtilTest.java @@ -181,12 +181,12 @@ public class StrUtilTest { @Test public void replaceTest() { - String string = StrUtil.replace("aabbccdd", 2, 6, '*'); + String string = StrUtil.replaceByCodePoint("aabbccdd", 2, 6, '*'); Assertions.assertEquals("aa****dd", string); - string = StrUtil.replace("aabbccdd", 2, 12, '*'); + string = StrUtil.replaceByCodePoint("aabbccdd", 2, 12, '*'); Assertions.assertEquals("aa******", string); - final String emoji = StrUtil.replace("\uD83D\uDE00aabb\uD83D\uDE00ccdd", 2, 6, '*'); + final String emoji = StrUtil.replaceByCodePoint("\uD83D\uDE00aabb\uD83D\uDE00ccdd", 2, 6, '*'); Assertions.assertEquals("\uD83D\uDE00a****ccdd", emoji); } @@ -210,11 +210,11 @@ public class StrUtilTest { @Test public void replaceTest5() { final String a = "\uD853\uDC09秀秀"; - final String result = StrUtil.replace(a, 1, a.length(), '*'); + final String result = StrUtil.replaceByCodePoint(a, 1, a.length(), '*'); Assertions.assertEquals("\uD853\uDC09**", result); final String aa = "规划大师"; - final String result1 = StrUtil.replace(aa, 2, a.length(), '*'); + final String result1 = StrUtil.replaceByCodePoint(aa, 2, a.length(), '*'); Assertions.assertEquals("规划**", result1); } @@ -602,10 +602,10 @@ public class StrUtilTest { @Test public void testReplaceByStr() { final String replace = "SSM15930297701BeryAllen"; - final String result = StrUtil.replace(replace, 5, 12, "***"); + final String result = StrUtil.replaceByCodePoint(replace, 5, 12, "***"); Assertions.assertEquals("SSM15***01BeryAllen", result); - final String emoji = StrUtil.replace("\uD83D\uDE00aabb\uD83D\uDE00ccdd", 2, 6, "***"); + final String emoji = StrUtil.replaceByCodePoint("\uD83D\uDE00aabb\uD83D\uDE00ccdd", 2, 6, "***"); Assertions.assertEquals("\uD83D\uDE00a***ccdd", emoji); }