From 2369beed8132a8acb57dfcfbe3d648abcc7b3735 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 30 Nov 2025 16:51:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D`HexUtil.format`=E5=9C=A8?= =?UTF-8?q?=E5=A4=84=E7=90=86=E9=95=BF=E5=BA=A6=E5=B0=8F=E4=BA=8E2?= =?UTF-8?q?=E7=9A=84=E5=AD=97=E7=AC=A6=E4=B8=B2=E4=BC=9A=E6=8A=9B=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=EF=BC=8C=E5=9C=A8=E5=A4=84=E7=90=86=E9=95=BF=E5=BA=A6?= =?UTF-8?q?=E4=B8=BA=E5=A5=87=E6=95=B0=E7=9A=84=E5=AD=97=E7=AC=A6=E4=B8=B2?= =?UTF-8?q?=E6=97=B6=E6=9C=80=E5=90=8E=E4=B8=80=E4=B8=AA=E5=AD=97=E7=AC=A6?= =?UTF-8?q?=E4=BC=9A=E8=A2=AB=E5=BF=BD=E7=95=A5=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=20=E4=BF=AE=E5=A4=8D`SplitIter.computeNext`=E9=80=92=E5=BD=92?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E5=8F=AF=E8=83=BD=E5=AF=BC=E8=87=B4=E6=A0=88?= =?UTF-8?q?=E6=BA=A2=E5=87=BA=E9=A3=8E=E9=99=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hutool/v7/core/codec/binary/HexUtil.java | 35 ++++++++++++--- .../hutool/v7/core/text/split/SplitIter.java | 39 ++++++++--------- .../v7/core/text/split/SplitIterTest.java | 43 +++++++++++++------ .../cn/hutool/v7/core/util/HexUtilTest.java | 30 +++++++++++++ 4 files changed, 109 insertions(+), 38 deletions(-) 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); + } }