mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-12-06 17:18:54 +08:00
Compare commits
6 Commits
882f3923ce
...
6bb750fb2c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bb750fb2c | ||
|
|
95c8e73c16 | ||
|
|
af97ba4084 | ||
|
|
8afee460fd | ||
|
|
0f60aa021a | ||
|
|
d821c410c6 |
@ -37,6 +37,8 @@
|
||||
* 【core 】 修复`DateModifier`处理AM和PM的ceiling和round问题(pr#4161@Github)
|
||||
* 【poi 】 修复`Word07Writer`run.setColor()的颜色十六进制转换逻辑(pr#4164@Github)
|
||||
* 【core 】 修复`Arrangement.iterate(int m)`方法的排列迭代器实现逻辑问题(pr#4166@Github)
|
||||
* 【core 】 修复`HexUtil.format`在处理长度小于2的字符串会抛异常,在处理长度为奇数的字符串时最后一个字符会被忽略的问题(pr#4168@Github)
|
||||
* 【core 】 修复`SplitIter.computeNext`递归调用可能导致栈溢出风险(pr#4168@Github)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
# 5.8.41(2025-10-12)
|
||||
|
||||
@ -114,7 +114,7 @@ public final class CsvParser extends ComputeIter<CsvRow> implements Closeable, S
|
||||
/**
|
||||
* 读取下一行数据
|
||||
*
|
||||
* @return CsvRow,{@code null}表示
|
||||
* @return CsvRow,{@code null}表示读取结束
|
||||
* @throws IORuntimeException IO读取异常
|
||||
*/
|
||||
public CsvRow nextRow() throws IORuntimeException {
|
||||
|
||||
@ -71,29 +71,28 @@ public class SplitIter extends ComputeIter<String> 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 (false == ignoreEmpty || false == result.isEmpty()) {
|
||||
// 返回非空串
|
||||
offset = Integer.MAX_VALUE;
|
||||
return result;
|
||||
String result = null;
|
||||
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;
|
||||
|
||||
@ -379,15 +379,24 @@ public class HexUtil {
|
||||
* @return 格式化后的字符串
|
||||
*/
|
||||
public static String format(final String hexStr, String prefix) {
|
||||
if (StrUtil.isEmpty(hexStr)) {
|
||||
return StrUtil.EMPTY;
|
||||
}
|
||||
if (null == prefix) {
|
||||
prefix = StrUtil.EMPTY;
|
||||
}
|
||||
|
||||
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(CharUtil.SPACE);
|
||||
}
|
||||
builder.append(prefix);
|
||||
}
|
||||
builder.append(hexStr.charAt(i));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@ -6,6 +6,8 @@ import cn.hutool.core.text.finder.PatternFinder;
|
||||
import cn.hutool.core.text.finder.StrFinder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -153,4 +155,18 @@ public class SplitIterTest {
|
||||
assertEquals(1, strings.size());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void issue4169Test() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < 20000; i++) { // 1万次连续分隔符,模拟递归深度风险场景
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append("test");
|
||||
|
||||
SplitIter iter = new SplitIter(sb.toString(), new StrFinder(",",false), 0, true);
|
||||
List<String> result = iter.toList(false);
|
||||
|
||||
assertEquals(Collections.singletonList("test"), result);
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,4 +116,35 @@ public class HexUtilTest {
|
||||
final String hex3 = "#FF";
|
||||
assertEquals(new BigInteger("FF", 16), HexUtil.toBigInteger(hex3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatEmpty() {
|
||||
String result = HexUtil.format("");
|
||||
assertEquals("", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatSingleChar() {
|
||||
String result = HexUtil.format("1");
|
||||
assertEquals("1", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatOddLength() {
|
||||
String result = HexUtil.format("123");
|
||||
assertEquals("12 3", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatWithPrefixSingleChar() {
|
||||
String result = HexUtil.format("1", "0x");
|
||||
assertEquals("0x1", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatWithPrefixOddLength() {
|
||||
String result = HexUtil.format("123", "0x");
|
||||
assertEquals("0x12 0x3", result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
package cn.hutool.poi.excel;
|
||||
|
||||
import cn.hutool.poi.excel.style.StyleUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import org.apache.poi.ss.usermodel.BorderStyle;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.FillPatternType;
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Issue4146Test {
|
||||
@Test
|
||||
@Disabled
|
||||
public void writeSheetWithStyleTest() {
|
||||
ExcelWriter writer = ExcelUtil.getWriter("d:\\test\\issue4146.xlsx", "表格1");
|
||||
|
||||
List<TestUser> list = new ArrayList<>();
|
||||
TestUser test = new TestUser("张三", 18, 90.0, 0.9878);
|
||||
list.add(test);
|
||||
test = new TestUser("李四", 18, 79.5, 0.8311);
|
||||
list.add(test);
|
||||
test = new TestUser("王五", 18, 89.9, 0.6932);
|
||||
list.add(test);
|
||||
test = new TestUser("赵六", 18, 69.9, 0.7912);
|
||||
list.add(test);
|
||||
test = new TestUser("孙七", 18, 79.9, 0.6432);
|
||||
list.add(test);
|
||||
|
||||
writer.addHeaderAlias("name", "姓名");
|
||||
writer.addHeaderAlias("age", "年龄");
|
||||
writer.addHeaderAlias("score", "分数");
|
||||
writer.addHeaderAlias("zb", "占比");
|
||||
|
||||
writer.setOnlyAlias(true);
|
||||
writer.write(list, true);
|
||||
|
||||
// 百分比的单元格样式必须单独创建,使用StyleSet中的样式修改则会修改全局样式
|
||||
CellStyle percentCellStyle = writer.createCellStyle();
|
||||
percentCellStyle.setDataFormat(writer.getWorkbook().createDataFormat().getFormat("0.00%"));
|
||||
// 填充背景颜色,必须指定FillPatternType才有效
|
||||
StyleUtil.setColor(percentCellStyle, IndexedColors.YELLOW, FillPatternType.SOLID_FOREGROUND);
|
||||
// 设置边框颜色和粗细
|
||||
StyleUtil.setBorder(percentCellStyle, BorderStyle.THIN, IndexedColors.BLACK);
|
||||
final int rowCount = writer.getRowCount();
|
||||
// 设置列样式无效,除非将默认样式清除,因此必须在写出数据后为单元格指定自定义的样式
|
||||
for (int i = 1; i < rowCount; i++) {
|
||||
writer.setStyle(percentCellStyle, 3, i);
|
||||
}
|
||||
|
||||
writer.close();
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
static class TestUser {
|
||||
private String name;
|
||||
private Integer age;
|
||||
private Double score;
|
||||
private Double zb;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user