diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/codec/binary/HexUtil.java b/hutool-core/src/main/java/cn/hutool/v7/core/codec/binary/HexUtil.java index 5c567247e..59c0212da 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/codec/binary/HexUtil.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/codec/binary/HexUtil.java @@ -16,7 +16,6 @@ package cn.hutool.v7.core.codec.binary; -import cn.hutool.v7.core.text.CharUtil; import cn.hutool.v7.core.text.StrUtil; import java.awt.Color; @@ -249,16 +248,42 @@ public class HexUtil extends Hex { * @param prefix 自定义前缀,如0x * @return 格式化后的字符串 */ - public static String format(final String hexStr, String prefix) { + public static String format(final String hexStr, final String prefix) { + return format(hexStr, prefix, StrUtil.SPACE); + } + + /** + * 格式化Hex字符串,结果为每2位加一个空格,类似于: + *
+	 *     e8 8c 67 03 80 cb 22 00 95 26 8f
+	 * 
+ * + * @param hexStr Hex字符串 + * @param prefix 自定义前缀,如0x + * @param separator 自定义分隔符,如空格 + * @return 格式化后的字符串 + */ + public static String format(final String hexStr, String prefix, String separator) { + if (StrUtil.isEmpty(hexStr)) { + return StrUtil.EMPTY; + } if (null == prefix) { prefix = StrUtil.EMPTY; } + if (null == separator) { + separator = StrUtil.SPACE; + } final int length = hexStr.length(); final StringBuilder builder = StrUtil.builder(length + length / 2 + (length / 2 * prefix.length())); - builder.append(prefix).append(hexStr.charAt(0)).append(hexStr.charAt(1)); - for (int i = 2; i < length - 1; i += 2) { - builder.append(CharUtil.SPACE).append(prefix).append(hexStr.charAt(i)).append(hexStr.charAt(i + 1)); + for (int i = 0; i < length; i++) { + if (i % 2 == 0) { + if (i != 0) { + builder.append(separator); + } + builder.append(prefix); + } + builder.append(hexStr.charAt(i)); } return builder.toString(); } diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/text/split/SplitIter.java b/hutool-core/src/main/java/cn/hutool/v7/core/text/split/SplitIter.java index 869dbabdc..6ce62d540 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/text/split/SplitIter.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/text/split/SplitIter.java @@ -89,29 +89,28 @@ public class SplitIter extends ComputeIter implements Serializable { return text.substring(offset); } - final int start = finder.start(offset); - // 无分隔符,结束 - if (start < 0) { - // 如果不再有分隔符,但是遗留了字符,则单独作为一个段 - if (offset <= text.length()) { - final String result = text.substring(offset); - if (!ignoreEmpty || !result.isEmpty()) { - // 返回非空串 - offset = Integer.MAX_VALUE; - return result; + String result; + int start; + do { + start = finder.start(offset); + // 无分隔符,结束 + if (start < 0) { + // 如果不再有分隔符,但是遗留了字符,则单独作为一个段 + if (offset <= text.length()) { + result = text.substring(offset); + if (!ignoreEmpty || !result.isEmpty()) { + // 返回非空串 + offset = Integer.MAX_VALUE; + return result; + } } + return null; } - return null; - } - // 找到新的分隔符位置 - final String result = text.substring(offset, start); - offset = finder.end(start); - - if (ignoreEmpty && result.isEmpty()) { - // 发现空串且需要忽略时,跳过之 - return computeNext(); - } + // 找到新的分隔符位置 + result = text.substring(offset, start); + offset = finder.end(start); + } while (ignoreEmpty && result.isEmpty()); // 空串则继续循环 count++; return result; diff --git a/hutool-core/src/test/java/cn/hutool/v7/core/text/split/SplitIterTest.java b/hutool-core/src/test/java/cn/hutool/v7/core/text/split/SplitIterTest.java index d491e9235..c8406ea4f 100644 --- a/hutool-core/src/test/java/cn/hutool/v7/core/text/split/SplitIterTest.java +++ b/hutool-core/src/test/java/cn/hutool/v7/core/text/split/SplitIterTest.java @@ -23,9 +23,12 @@ import cn.hutool.v7.core.text.finder.StrFinder; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.util.Collections; import java.util.List; import java.util.regex.Pattern; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class SplitIterTest { @Test @@ -38,7 +41,7 @@ public class SplitIterTest { Integer.MAX_VALUE, false ); - Assertions.assertEquals(6, splitIter.toList(false).size()); + assertEquals(6, splitIter.toList(false).size()); } @Test @@ -51,7 +54,7 @@ public class SplitIterTest { Integer.MAX_VALUE, false ); - Assertions.assertEquals(4, splitIter.toList(false).size()); + assertEquals(4, splitIter.toList(false).size()); } @Test @@ -65,7 +68,7 @@ public class SplitIterTest { ); final List strings = splitIter.toList(false); - Assertions.assertEquals(4, strings.size()); + assertEquals(4, strings.size()); } @Test @@ -79,10 +82,10 @@ public class SplitIterTest { ); final List strings = splitIter.toList(true); - Assertions.assertEquals(3, strings.size()); - Assertions.assertEquals("a", strings.get(0)); - Assertions.assertEquals("efedsfs", strings.get(1)); - Assertions.assertEquals("ddf", strings.get(2)); + assertEquals(3, strings.size()); + assertEquals("a", strings.get(0)); + assertEquals("efedsfs", strings.get(1)); + assertEquals("ddf", strings.get(2)); } @Test @@ -96,7 +99,7 @@ public class SplitIterTest { ); final List strings = splitIter.toList(false); - Assertions.assertEquals(3, strings.size()); + assertEquals(3, strings.size()); } @Test @@ -110,7 +113,7 @@ public class SplitIterTest { ); final List strings = splitIter.toList(false); - Assertions.assertEquals(3, strings.size()); + assertEquals(3, strings.size()); } @Test @@ -123,7 +126,7 @@ public class SplitIterTest { ); final List strings = splitIter.toList(false); - Assertions.assertEquals(4, strings.size()); + assertEquals(4, strings.size()); } @Test @@ -136,7 +139,7 @@ public class SplitIterTest { ); final List strings = splitIter.toList(false); - Assertions.assertEquals(3, strings.size()); + assertEquals(3, strings.size()); } @Test @@ -149,7 +152,7 @@ public class SplitIterTest { ); final List strings = splitIter.toList(false); - Assertions.assertEquals(1, strings.size()); + assertEquals(1, strings.size()); } // 切割字符串是空字符串时报错 @@ -164,7 +167,21 @@ public class SplitIterTest { ); final List strings = splitIter.toList(false); - Assertions.assertEquals(1, strings.size()); + assertEquals(1, strings.size()); }); } + + @Test + public void issue4169Test() { + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 20000; i++) { // 1万次连续分隔符,模拟递归深度风险场景 + sb.append(","); + } + sb.append("test"); + + final SplitIter iter = new SplitIter(sb.toString(), new StrFinder(",",false), 0, true); + final List result = iter.toList(false); + + assertEquals(Collections.singletonList("test"), result); + } } diff --git a/hutool-core/src/test/java/cn/hutool/v7/core/util/HexUtilTest.java b/hutool-core/src/test/java/cn/hutool/v7/core/util/HexUtilTest.java index 8cc4e564a..3c14f9b55 100644 --- a/hutool-core/src/test/java/cn/hutool/v7/core/util/HexUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/v7/core/util/HexUtilTest.java @@ -135,4 +135,34 @@ public class HexUtilTest { final String hex3 = "#FF"; assertEquals(new BigInteger("FF", 16), HexUtil.toBigInteger(hex3)); } + + @Test + public void testFormatEmpty() { + final String result = HexUtil.format(""); + assertEquals("", result); + } + + @Test + public void testFormatSingleChar() { + final String result = HexUtil.format("1"); + assertEquals("1", result); + } + + @Test + public void testFormatOddLength() { + final String result = HexUtil.format("123"); + assertEquals("12 3", result); + } + + @Test + public void testFormatWithPrefixSingleChar() { + final String result = HexUtil.format("1", "0x"); + assertEquals("0x1", result); + } + + @Test + public void testFormatWithPrefixOddLength() { + final String result = HexUtil.format("123", "0x"); + assertEquals("0x12 0x3", result); + } }