This commit is contained in:
Looly 2024-03-07 16:03:57 +08:00
parent 27d67c4d84
commit 197e89e692
6 changed files with 75 additions and 25 deletions

View File

@ -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, '*');
}
/**

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -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());
}
}

View File

@ -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);
}