mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
fix code
This commit is contained in:
parent
bece00d176
commit
9f9efdcef4
@ -43,6 +43,7 @@ public class NumberUtil {
|
|||||||
*/
|
*/
|
||||||
private static final int DEFAULT_DIV_SCALE = 10;
|
private static final int DEFAULT_DIV_SCALE = 10;
|
||||||
|
|
||||||
|
// region ----- add
|
||||||
/**
|
/**
|
||||||
* 提供精确的加法运算<br>
|
* 提供精确的加法运算<br>
|
||||||
* 如果传入多个值为null或者空,则返回0
|
* 如果传入多个值为null或者空,则返回0
|
||||||
@ -90,7 +91,9 @@ public class NumberUtil {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region ----- sub
|
||||||
/**
|
/**
|
||||||
* 提供精确的减法运算<br>
|
* 提供精确的减法运算<br>
|
||||||
* 如果传入多个值为null或者空,则返回0
|
* 如果传入多个值为null或者空,则返回0
|
||||||
@ -138,7 +141,9 @@ public class NumberUtil {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region ----- mul
|
||||||
/**
|
/**
|
||||||
* 提供精确的乘法运算<br>
|
* 提供精确的乘法运算<br>
|
||||||
* 如果传入多个值为null或者空,则返回0
|
* 如果传入多个值为null或者空,则返回0
|
||||||
@ -181,7 +186,9 @@ public class NumberUtil {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region ----- div
|
||||||
/**
|
/**
|
||||||
* 提供(相对)精确的除法运算,当发生除不尽的情况的时候,精确到小数点后10位,后面的四舍五入
|
* 提供(相对)精确的除法运算,当发生除不尽的情况的时候,精确到小数点后10位,后面的四舍五入
|
||||||
*
|
*
|
||||||
@ -278,8 +285,9 @@ public class NumberUtil {
|
|||||||
public static int ceilDiv(final int v1, final int v2) {
|
public static int ceilDiv(final int v1, final int v2) {
|
||||||
return (int) Math.ceil((double) v1 / v2);
|
return (int) Math.ceil((double) v1 / v2);
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------- round
|
// region ----- round
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保留固定位数小数<br>
|
* 保留固定位数小数<br>
|
||||||
@ -500,8 +508,9 @@ public class NumberUtil {
|
|||||||
public static BigDecimal roundDown(final BigDecimal value, final int scale) {
|
public static BigDecimal roundDown(final BigDecimal value, final int scale) {
|
||||||
return round(value, scale, RoundingMode.DOWN);
|
return round(value, scale, RoundingMode.DOWN);
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------- decimalFormat
|
// region ----- decimalFormat
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 格式化double<br>
|
* 格式化double<br>
|
||||||
@ -627,8 +636,9 @@ public class NumberUtil {
|
|||||||
format.setMaximumFractionDigits(scale);
|
format.setMaximumFractionDigits(scale);
|
||||||
return format.format(number);
|
return format.format(number);
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------- isXXX
|
// region ----- isXXX
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否为数字,支持包括:
|
* 是否为数字,支持包括:
|
||||||
@ -853,8 +863,9 @@ public class NumberUtil {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------- range
|
// region ----- range
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成一个从0开始的数字列表<br>
|
* 生成一个从0开始的数字列表<br>
|
||||||
@ -947,6 +958,7 @@ public class NumberUtil {
|
|||||||
}
|
}
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------- others
|
// ------------------------------------------------------------------------------------------- others
|
||||||
|
|
||||||
@ -986,6 +998,7 @@ public class NumberUtil {
|
|||||||
return Long.parseLong(binaryStr, 2);
|
return Long.parseLong(binaryStr, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// region ----- equals
|
||||||
/**
|
/**
|
||||||
* 比较大小,值相等 返回true<br>
|
* 比较大小,值相等 返回true<br>
|
||||||
* 此方法通过调用{@link Double#doubleToLongBits(double)}方法来判断是否相等<br>
|
* 此方法通过调用{@link Double#doubleToLongBits(double)}方法来判断是否相等<br>
|
||||||
@ -1054,7 +1067,9 @@ public class NumberUtil {
|
|||||||
public static boolean equals(final char c1, final char c2, final boolean ignoreCase) {
|
public static boolean equals(final char c1, final char c2, final boolean ignoreCase) {
|
||||||
return CharUtil.equals(c1, c2, ignoreCase);
|
return CharUtil.equals(c1, c2, ignoreCase);
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region ----- toStr
|
||||||
/**
|
/**
|
||||||
* 数字转字符串<br>
|
* 数字转字符串<br>
|
||||||
* 调用{@link Number#toString()},并去除尾小数点儿后多余的0
|
* 调用{@link Number#toString()},并去除尾小数点儿后多余的0
|
||||||
@ -1139,6 +1154,7 @@ public class NumberUtil {
|
|||||||
}
|
}
|
||||||
return bigDecimal.toPlainString();
|
return bigDecimal.toPlainString();
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数字转{@link BigDecimal}<br>
|
* 数字转{@link BigDecimal}<br>
|
||||||
@ -1399,6 +1415,7 @@ public class NumberUtil {
|
|||||||
return (n > 0) && ((n & (n - 1)) == 0);
|
return (n > 0) && ((n & (n - 1)) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// region ----- parse
|
||||||
/**
|
/**
|
||||||
* 解析转换数字字符串为 {@link java.lang.Integer } 规则如下:
|
* 解析转换数字字符串为 {@link java.lang.Integer } 规则如下:
|
||||||
*
|
*
|
||||||
@ -1680,6 +1697,7 @@ public class NumberUtil {
|
|||||||
throw nfe;
|
throw nfe;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查是否为有效的数字<br>
|
* 检查是否为有效的数字<br>
|
||||||
|
@ -11,6 +11,9 @@ import cn.hutool.core.text.finder.CharFinder;
|
|||||||
import cn.hutool.core.text.finder.CharMatcherFinder;
|
import cn.hutool.core.text.finder.CharMatcherFinder;
|
||||||
import cn.hutool.core.text.finder.Finder;
|
import cn.hutool.core.text.finder.Finder;
|
||||||
import cn.hutool.core.text.finder.StrFinder;
|
import cn.hutool.core.text.finder.StrFinder;
|
||||||
|
import cn.hutool.core.text.replacer.RangeReplacerByChar;
|
||||||
|
import cn.hutool.core.text.replacer.RangeReplacerByStr;
|
||||||
|
import cn.hutool.core.text.replacer.SearchReplacer;
|
||||||
import cn.hutool.core.text.split.SplitUtil;
|
import cn.hutool.core.text.split.SplitUtil;
|
||||||
import cn.hutool.core.util.*;
|
import cn.hutool.core.util.*;
|
||||||
|
|
||||||
@ -3263,7 +3266,8 @@ public class CharSequenceUtil extends StrChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 替换字符串中的指定字符串
|
* 替换字符串中的指定字符串<br>
|
||||||
|
* 如果指定字符串出现多次,则全部替换
|
||||||
*
|
*
|
||||||
* @param str 字符串
|
* @param str 字符串
|
||||||
* @param fromIndex 开始位置(包括)
|
* @param fromIndex 开始位置(包括)
|
||||||
@ -3273,85 +3277,27 @@ public class CharSequenceUtil extends StrChecker {
|
|||||||
* @return 替换后的字符串
|
* @return 替换后的字符串
|
||||||
* @since 4.0.3
|
* @since 4.0.3
|
||||||
*/
|
*/
|
||||||
public static String replace(final CharSequence str, int fromIndex, final CharSequence searchStr, CharSequence replacement, final boolean ignoreCase) {
|
public static String replace(final CharSequence str, final int fromIndex, final CharSequence searchStr, final CharSequence replacement, final boolean ignoreCase) {
|
||||||
if (isEmpty(str) || isEmpty(searchStr)) {
|
if (isEmpty(str) || isEmpty(searchStr)) {
|
||||||
return str(str);
|
return str(str);
|
||||||
}
|
}
|
||||||
if (null == replacement) {
|
return new SearchReplacer(fromIndex, searchStr, replacement, ignoreCase).apply(str);
|
||||||
replacement = EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int strLength = str.length();
|
|
||||||
final int searchStrLength = searchStr.length();
|
|
||||||
if (strLength < searchStrLength) {
|
|
||||||
// issue#I4M16G@Gitee
|
|
||||||
return str(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fromIndex > strLength) {
|
|
||||||
return str(str);
|
|
||||||
} else if (fromIndex < 0) {
|
|
||||||
fromIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
final StringBuilder result = new StringBuilder(strLength - searchStrLength + replacement.length());
|
|
||||||
if (0 != fromIndex) {
|
|
||||||
result.append(str.subSequence(0, fromIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
int preIndex = fromIndex;
|
|
||||||
int index;
|
|
||||||
while ((index = indexOf(str, searchStr, preIndex, ignoreCase)) > -1) {
|
|
||||||
result.append(str.subSequence(preIndex, index));
|
|
||||||
result.append(replacement);
|
|
||||||
preIndex = index + searchStrLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preIndex < strLength) {
|
|
||||||
// 结尾部分
|
|
||||||
result.append(str.subSequence(preIndex, strLength));
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 替换指定字符串的指定区间内字符为固定字符<br>
|
* 替换指定字符串的指定区间内字符为固定字符,替换后字符串长度不变<br>
|
||||||
|
* 如替换的区间长度为10,则替换后的字符重复10次<br>
|
||||||
* 此方法使用{@link String#codePoints()}完成拆分替换
|
* 此方法使用{@link String#codePoints()}完成拆分替换
|
||||||
*
|
*
|
||||||
* @param str 字符串
|
* @param str 字符串
|
||||||
* @param startInclude 开始位置(包含)
|
* @param beginInclude 开始位置(包含)
|
||||||
* @param endExclude 结束位置(不包含)
|
* @param endExclude 结束位置(不包含)
|
||||||
* @param replacedChar 被替换的字符
|
* @param replacedChar 被替换的字符
|
||||||
* @return 替换后的字符串
|
* @return 替换后的字符串
|
||||||
* @since 3.2.1
|
* @since 3.2.1
|
||||||
*/
|
*/
|
||||||
public static String replace(final CharSequence str, final int startInclude, int endExclude, final char replacedChar) {
|
public static String replace(final CharSequence str, final int beginInclude, final int endExclude, final char replacedChar) {
|
||||||
if (isEmpty(str)) {
|
return new RangeReplacerByChar(beginInclude, endExclude, replacedChar).apply(str);
|
||||||
return str(str);
|
|
||||||
}
|
|
||||||
final String originalStr = str(str);
|
|
||||||
final int[] strCodePoints = originalStr.codePoints().toArray();
|
|
||||||
final int strLength = strCodePoints.length;
|
|
||||||
if (startInclude > strLength) {
|
|
||||||
return originalStr;
|
|
||||||
}
|
|
||||||
if (endExclude > strLength) {
|
|
||||||
endExclude = strLength;
|
|
||||||
}
|
|
||||||
if (startInclude > endExclude) {
|
|
||||||
// 如果起始位置大于结束位置,不替换
|
|
||||||
return originalStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
final StringBuilder stringBuilder = new StringBuilder(originalStr.length());
|
|
||||||
for (int i = 0; i < strLength; i++) {
|
|
||||||
if (i >= startInclude && i < endExclude) {
|
|
||||||
stringBuilder.append(replacedChar);
|
|
||||||
} else {
|
|
||||||
stringBuilder.appendCodePoint(strCodePoints[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return stringBuilder.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3359,40 +3305,14 @@ public class CharSequenceUtil extends StrChecker {
|
|||||||
* 此方法使用{@link String#codePoints()}完成拆分替换
|
* 此方法使用{@link String#codePoints()}完成拆分替换
|
||||||
*
|
*
|
||||||
* @param str 字符串
|
* @param str 字符串
|
||||||
* @param startInclude 开始位置(包含)
|
* @param beginInclude 开始位置(包含)
|
||||||
* @param endExclude 结束位置(不包含)
|
* @param endExclude 结束位置(不包含)
|
||||||
* @param replacedStr 被替换的字符串
|
* @param replacedStr 被替换的字符串
|
||||||
* @return 替换后的字符串
|
* @return 替换后的字符串
|
||||||
* @since 3.2.1
|
* @since 3.2.1
|
||||||
*/
|
*/
|
||||||
public static String replace(final CharSequence str, final int startInclude, int endExclude, final CharSequence replacedStr) {
|
public static String replace(final CharSequence str, final int beginInclude, final int endExclude, final CharSequence replacedStr) {
|
||||||
if (isEmpty(str)) {
|
return new RangeReplacerByStr(beginInclude, endExclude, replacedStr).apply(str);
|
||||||
return str(str);
|
|
||||||
}
|
|
||||||
final String originalStr = str(str);
|
|
||||||
final int[] strCodePoints = originalStr.codePoints().toArray();
|
|
||||||
final int strLength = strCodePoints.length;
|
|
||||||
if (startInclude > strLength) {
|
|
||||||
return originalStr;
|
|
||||||
}
|
|
||||||
if (endExclude > strLength) {
|
|
||||||
endExclude = strLength;
|
|
||||||
}
|
|
||||||
if (startInclude > endExclude) {
|
|
||||||
// 如果起始位置大于结束位置,不替换
|
|
||||||
return originalStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新字符串长度 <= 旧长度 - (被替换区间codePoints数量) + 替换字符串长度
|
|
||||||
final StringBuilder stringBuilder = new StringBuilder(originalStr.length() - (endExclude - startInclude) + replacedStr.length());
|
|
||||||
for (int i = 0; i < startInclude; i++) {
|
|
||||||
stringBuilder.appendCodePoint(strCodePoints[i]);
|
|
||||||
}
|
|
||||||
stringBuilder.append(replacedStr);
|
|
||||||
for (int i = endExclude; i < strLength; i++) {
|
|
||||||
stringBuilder.appendCodePoint(strCodePoints[i]);
|
|
||||||
}
|
|
||||||
return stringBuilder.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
package cn.hutool.core.text.replacer;
|
||||||
|
|
||||||
|
import cn.hutool.core.text.StrUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 区间字符串替换,指定区间,将区间中的所有字符去除,替换为指定的字符,字符重复次数为区间长度,即替换后字符串长度不变<br>
|
||||||
|
* 此方法使用{@link String#codePoints()}完成拆分替换
|
||||||
|
*
|
||||||
|
* @author Looly
|
||||||
|
*/
|
||||||
|
public class RangeReplacerByChar extends StrReplacer {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final int beginInclude;
|
||||||
|
private final int endExclude;
|
||||||
|
private final char replacedChar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param beginInclude 开始位置(包含)
|
||||||
|
* @param endExclude 结束位置(不包含)
|
||||||
|
* @param replacedChar 被替换的字符串
|
||||||
|
*/
|
||||||
|
public RangeReplacerByChar(final int beginInclude, final int endExclude, final char replacedChar) {
|
||||||
|
this.beginInclude = beginInclude;
|
||||||
|
this.endExclude = endExclude;
|
||||||
|
this.replacedChar = replacedChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String apply(final CharSequence str) {
|
||||||
|
if (StrUtil.isEmpty(str)) {
|
||||||
|
return StrUtil.str(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String originalStr = StrUtil.str(str);
|
||||||
|
final int[] strCodePoints = originalStr.codePoints().toArray();
|
||||||
|
final int strLength = strCodePoints.length;
|
||||||
|
|
||||||
|
final int beginInclude = this.beginInclude;
|
||||||
|
if (beginInclude > strLength) {
|
||||||
|
return originalStr;
|
||||||
|
}
|
||||||
|
int endExclude = this.endExclude;
|
||||||
|
if (endExclude > strLength) {
|
||||||
|
endExclude = strLength;
|
||||||
|
}
|
||||||
|
if (beginInclude > endExclude) {
|
||||||
|
// 如果起始位置大于结束位置,不替换
|
||||||
|
return originalStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新字符串长度不变
|
||||||
|
final StringBuilder stringBuilder = new StringBuilder(originalStr.length());
|
||||||
|
for (int i = 0; i < strLength; i++) {
|
||||||
|
if (i >= beginInclude && i < endExclude) {
|
||||||
|
// 区间内的字符全部替换
|
||||||
|
replace(originalStr, i, stringBuilder);
|
||||||
|
} else {
|
||||||
|
// 其它字符保留
|
||||||
|
stringBuilder.appendCodePoint(strCodePoints[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int replace(final CharSequence str, final int pos, final StringBuilder out) {
|
||||||
|
out.appendCodePoint(replacedChar);
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
package cn.hutool.core.text.replacer;
|
||||||
|
|
||||||
|
import cn.hutool.core.text.StrUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 区间字符串替换,指定区间,将区间中的所有字符去除,替换为指定的字符串,字符串只重复一次<br>
|
||||||
|
* 此方法使用{@link String#codePoints()}完成拆分替换
|
||||||
|
*
|
||||||
|
* @author Looly
|
||||||
|
*/
|
||||||
|
public class RangeReplacerByStr extends StrReplacer {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final int beginInclude;
|
||||||
|
private final int endExclude;
|
||||||
|
private final CharSequence replacedStr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param beginInclude 开始位置(包含)
|
||||||
|
* @param endExclude 结束位置(不包含)
|
||||||
|
* @param replacedStr 被替换的字符串
|
||||||
|
*/
|
||||||
|
public RangeReplacerByStr(final int beginInclude, final int endExclude, final CharSequence replacedStr) {
|
||||||
|
this.beginInclude = beginInclude;
|
||||||
|
this.endExclude = endExclude;
|
||||||
|
this.replacedStr = replacedStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String apply(final CharSequence str) {
|
||||||
|
if (StrUtil.isEmpty(str)) {
|
||||||
|
return StrUtil.str(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String originalStr = StrUtil.str(str);
|
||||||
|
final int[] strCodePoints = originalStr.codePoints().toArray();
|
||||||
|
final int strLength = strCodePoints.length;
|
||||||
|
|
||||||
|
final int beginInclude = this.beginInclude;
|
||||||
|
if (beginInclude > strLength) {
|
||||||
|
return originalStr;
|
||||||
|
}
|
||||||
|
int endExclude = this.endExclude;
|
||||||
|
if (endExclude > strLength) {
|
||||||
|
endExclude = strLength;
|
||||||
|
}
|
||||||
|
if (beginInclude > endExclude) {
|
||||||
|
// 如果起始位置大于结束位置,不替换
|
||||||
|
return originalStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新字符串长度 <= 旧长度 - (被替换区间codePoints数量) + 替换字符串长度
|
||||||
|
final StringBuilder stringBuilder = new StringBuilder(originalStr.length() - (endExclude - beginInclude) + replacedStr.length());
|
||||||
|
for (int i = 0; i < beginInclude; i++) {
|
||||||
|
stringBuilder.appendCodePoint(strCodePoints[i]);
|
||||||
|
}
|
||||||
|
replace(originalStr, beginInclude, stringBuilder);
|
||||||
|
for (int i = endExclude; i < strLength; i++) {
|
||||||
|
stringBuilder.appendCodePoint(strCodePoints[i]);
|
||||||
|
}
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int replace(final CharSequence str, final int pos, final StringBuilder out) {
|
||||||
|
// 由于区间替换,因此区间已确定,直接替换即可
|
||||||
|
out.append(this.replacedStr);
|
||||||
|
|
||||||
|
// 无意义的返回
|
||||||
|
return endExclude;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
package cn.hutool.core.text.replacer;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.text.StrUtil;
|
||||||
|
import cn.hutool.core.text.finder.Finder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找替换器<br>
|
||||||
|
* 查找给定的字符串,并全部替换为新的字符串,其它字符不变
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class SearchReplacer extends StrReplacer {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private static final int INDEX_NOT_FOUND = Finder.INDEX_NOT_FOUND;
|
||||||
|
|
||||||
|
private final int fromIndex;
|
||||||
|
private final CharSequence searchStr;
|
||||||
|
private final int searchStrLength;
|
||||||
|
private final CharSequence replacement;
|
||||||
|
private final boolean ignoreCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param fromIndex 开始位置(包括)
|
||||||
|
* @param searchStr 被查找的字符串
|
||||||
|
* @param replacement 被替换的字符串
|
||||||
|
* @param ignoreCase 是否忽略大小写
|
||||||
|
*/
|
||||||
|
public SearchReplacer(final int fromIndex, final CharSequence searchStr, final CharSequence replacement, final boolean ignoreCase) {
|
||||||
|
this.fromIndex = Math.max(fromIndex, 0);
|
||||||
|
this.searchStr = Assert.notEmpty(searchStr, "'searchStr' must be not empty!");
|
||||||
|
this.searchStrLength = searchStr.length();
|
||||||
|
this.replacement = StrUtil.emptyIfNull(replacement);
|
||||||
|
this.ignoreCase = ignoreCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String apply(final CharSequence str) {
|
||||||
|
if (StrUtil.isEmpty(str)) {
|
||||||
|
return StrUtil.str(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
final int strLength = str.length();
|
||||||
|
if (strLength < this.searchStrLength) {
|
||||||
|
// issue#I4M16G@Gitee
|
||||||
|
return StrUtil.str(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
final int fromIndex = this.fromIndex;
|
||||||
|
if (fromIndex > strLength) {
|
||||||
|
// 越界截断
|
||||||
|
return StrUtil.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
final StringBuilder result = new StringBuilder(
|
||||||
|
strLength - this.searchStrLength + this.replacement.length());
|
||||||
|
if (0 != fromIndex) {
|
||||||
|
// 开始部分
|
||||||
|
result.append(str.subSequence(0, fromIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 替换部分
|
||||||
|
int pos = fromIndex;
|
||||||
|
int consumed;//处理过的字符数
|
||||||
|
while ((consumed = replace(str, pos, result)) > 0) {
|
||||||
|
pos += consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos < strLength) {
|
||||||
|
// 结尾部分
|
||||||
|
result.append(str.subSequence(pos, strLength));
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int replace(final CharSequence str, final int pos, final StringBuilder out) {
|
||||||
|
final int index = StrUtil.indexOf(str, this.searchStr, pos, this.ignoreCase);
|
||||||
|
if (index > INDEX_NOT_FOUND) {
|
||||||
|
// 无需替换的部分
|
||||||
|
out.append(str.subSequence(pos, index));
|
||||||
|
// 替换的部分
|
||||||
|
out.append(replacement);
|
||||||
|
|
||||||
|
//已经处理的长度 = 无需替换的长度(查找字符串位置 - 开始的位置) + 替换的长度
|
||||||
|
return index - pos + searchStrLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 未找到
|
||||||
|
return INDEX_NOT_FOUND;
|
||||||
|
}
|
||||||
|
}
|
@ -23,17 +23,22 @@ public abstract class StrReplacer implements UnaryOperator<CharSequence>, Serial
|
|||||||
*/
|
*/
|
||||||
protected abstract int replace(CharSequence str, int pos, StringBuilder out);
|
protected abstract int replace(CharSequence str, int pos, StringBuilder out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行替换,按照{@link #replace(CharSequence, int, StringBuilder)}逻辑替换对应部分,其它部分保持原样
|
||||||
|
* @param str 被处理的字符串
|
||||||
|
* @return 替换后的字符串
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public CharSequence apply(final CharSequence t) {
|
public CharSequence apply(final CharSequence str) {
|
||||||
final int len = t.length();
|
final int len = str.length();
|
||||||
final StringBuilder builder = new StringBuilder(len);
|
final StringBuilder builder = new StringBuilder(len);
|
||||||
int pos = 0;//当前位置
|
int pos = 0;//当前位置
|
||||||
int consumed;//处理过的字符数
|
int consumed;//处理过的字符数
|
||||||
while (pos < len) {
|
while (pos < len) {
|
||||||
consumed = replace(t, pos, builder);
|
consumed = replace(str, pos, builder);
|
||||||
if (0 == consumed) {
|
if (0 == consumed) {
|
||||||
//0表示未处理或替换任何字符,原样输出本字符并从下一个字符继续
|
//0表示未处理或替换任何字符,原样输出本字符并从下一个字符继续
|
||||||
builder.append(t.charAt(pos));
|
builder.append(str.charAt(pos));
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
pos += consumed;
|
pos += consumed;
|
||||||
|
@ -221,7 +221,7 @@ public class StrUtilTest {
|
|||||||
string = StrUtil.replace("aabbccdd", 2, 12, '*');
|
string = StrUtil.replace("aabbccdd", 2, 12, '*');
|
||||||
Assert.assertEquals("aa******", string);
|
Assert.assertEquals("aa******", string);
|
||||||
|
|
||||||
String emoji = StrUtil.replace("\uD83D\uDE00aabb\uD83D\uDE00ccdd", 2, 6, '*');
|
final String emoji = StrUtil.replace("\uD83D\uDE00aabb\uD83D\uDE00ccdd", 2, 6, '*');
|
||||||
Assert.assertEquals("\uD83D\uDE00a****ccdd", emoji);
|
Assert.assertEquals("\uD83D\uDE00a****ccdd", emoji);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,12 +231,6 @@ public class StrUtilTest {
|
|||||||
Assert.assertEquals("133", result);
|
Assert.assertEquals("133", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void replaceTest3() {
|
|
||||||
final String result = StrUtil.replace(",abcdef,", ",", "|");
|
|
||||||
Assert.assertEquals("|abcdef|", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void replaceTest4() {
|
public void replaceTest4() {
|
||||||
final String a = "1039";
|
final String a = "1039";
|
||||||
@ -642,7 +636,7 @@ public class StrUtilTest {
|
|||||||
final String result = StrUtil.replace(replace, 5, 12, "***");
|
final String result = StrUtil.replace(replace, 5, 12, "***");
|
||||||
Assert.assertEquals("SSM15***01BeryAllen", result);
|
Assert.assertEquals("SSM15***01BeryAllen", result);
|
||||||
|
|
||||||
String emoji = StrUtil.replace("\uD83D\uDE00aabb\uD83D\uDE00ccdd", 2, 6, "***");
|
final String emoji = StrUtil.replace("\uD83D\uDE00aabb\uD83D\uDE00ccdd", 2, 6, "***");
|
||||||
Assert.assertEquals("\uD83D\uDE00a***ccdd", emoji);
|
Assert.assertEquals("\uD83D\uDE00a***ccdd", emoji);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
package cn.hutool.core.text.replacer;
|
||||||
|
|
||||||
|
import cn.hutool.core.text.CharSequenceUtil;
|
||||||
|
import cn.hutool.core.text.StrUtil;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class SearchReplacerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void replaceOnlyTest() {
|
||||||
|
final String result = CharSequenceUtil.replace(",", ",", "|");
|
||||||
|
Assert.assertEquals("|", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void replaceTestAtBeginAndEnd() {
|
||||||
|
final String result = CharSequenceUtil.replace(",abcdef,", ",", "|");
|
||||||
|
Assert.assertEquals("|abcdef|", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void replaceTest() {
|
||||||
|
final String str = "AAABBCCCBBDDDBB";
|
||||||
|
String replace = StrUtil.replace(str, 0, "BB", "22", false);
|
||||||
|
Assert.assertEquals("AAA22CCC22DDD22", replace);
|
||||||
|
|
||||||
|
replace = StrUtil.replace(str, 3, "BB", "22", false);
|
||||||
|
Assert.assertEquals("AAA22CCC22DDD22", replace);
|
||||||
|
|
||||||
|
replace = StrUtil.replace(str, 4, "BB", "22", false);
|
||||||
|
Assert.assertEquals("AAABBCCC22DDD22", replace);
|
||||||
|
|
||||||
|
replace = StrUtil.replace(str, 4, "bb", "22", true);
|
||||||
|
Assert.assertEquals("AAABBCCC22DDD22", replace);
|
||||||
|
|
||||||
|
replace = StrUtil.replace(str, 4, "bb", "", true);
|
||||||
|
Assert.assertEquals("AAABBCCCDDD", replace);
|
||||||
|
|
||||||
|
replace = StrUtil.replace(str, 4, "bb", null, true);
|
||||||
|
Assert.assertEquals("AAABBCCCDDD", replace);
|
||||||
|
}
|
||||||
|
}
|
@ -134,28 +134,6 @@ public class ReUtilTest {
|
|||||||
Assert.assertThrows(IllegalArgumentException.class, () -> ReUtil.replaceAll(content, pattern, str));
|
Assert.assertThrows(IllegalArgumentException.class, () -> ReUtil.replaceAll(content, pattern, str));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void replaceTest() {
|
|
||||||
final String str = "AAABBCCCBBDDDBB";
|
|
||||||
String replace = StrUtil.replace(str, 0, "BB", "22", false);
|
|
||||||
Assert.assertEquals("AAA22CCC22DDD22", replace);
|
|
||||||
|
|
||||||
replace = StrUtil.replace(str, 3, "BB", "22", false);
|
|
||||||
Assert.assertEquals("AAA22CCC22DDD22", replace);
|
|
||||||
|
|
||||||
replace = StrUtil.replace(str, 4, "BB", "22", false);
|
|
||||||
Assert.assertEquals("AAABBCCC22DDD22", replace);
|
|
||||||
|
|
||||||
replace = StrUtil.replace(str, 4, "bb", "22", true);
|
|
||||||
Assert.assertEquals("AAABBCCC22DDD22", replace);
|
|
||||||
|
|
||||||
replace = StrUtil.replace(str, 4, "bb", "", true);
|
|
||||||
Assert.assertEquals("AAABBCCCDDD", replace);
|
|
||||||
|
|
||||||
replace = StrUtil.replace(str, 4, "bb", null, true);
|
|
||||||
Assert.assertEquals("AAABBCCCDDD", replace);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void escapeTest() {
|
public void escapeTest() {
|
||||||
//转义给定字符串,为正则相关的特殊符号转义
|
//转义给定字符串,为正则相关的特殊符号转义
|
||||||
|
Loading…
x
Reference in New Issue
Block a user