mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
update StrTemplate;
This commit is contained in:
parent
40778dd924
commit
8a0327ac9c
@ -13,10 +13,7 @@ import org.dromara.hutool.core.text.placeholder.segment.StrTemplateSegment;
|
|||||||
import org.dromara.hutool.core.text.placeholder.template.NamedPlaceholderStrTemplate;
|
import org.dromara.hutool.core.text.placeholder.template.NamedPlaceholderStrTemplate;
|
||||||
import org.dromara.hutool.core.text.placeholder.template.SinglePlaceholderStrTemplate;
|
import org.dromara.hutool.core.text.placeholder.template.SinglePlaceholderStrTemplate;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
@ -276,10 +273,16 @@ public abstract class StrTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final StringBuilder sb = new StringBuilder(totalTextLength);
|
final StringBuilder sb = new StringBuilder(totalTextLength);
|
||||||
final Iterator<String> valueIterator = values.iterator();
|
int index = 0;
|
||||||
// 构造格式化结果字符串
|
// 构造格式化结果字符串
|
||||||
for (StrTemplateSegment segment : segments) {
|
for (StrTemplateSegment segment : segments) {
|
||||||
segment.format(sb, valueIterator);
|
if (segment instanceof LiteralSegment) {
|
||||||
|
sb.append(segment.getText());
|
||||||
|
}
|
||||||
|
// 当前是 占位符,直接 替换为 参数值
|
||||||
|
else {
|
||||||
|
sb.append(values.get(index++));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
@ -596,8 +599,8 @@ public abstract class StrTemplate {
|
|||||||
* <p>由于此时子类还没构造完成,所以只能由子类构造方法调用</p>
|
* <p>由于此时子类还没构造完成,所以只能由子类构造方法调用</p>
|
||||||
*/
|
*/
|
||||||
protected void afterInit() {
|
protected void afterInit() {
|
||||||
// 解析 并 优化 segment 列表
|
// 释放空闲的列表元素
|
||||||
this.segments = optimizeSegments(parseSegments(template));
|
this.segments = new ArrayList<>(parseSegments(template));
|
||||||
|
|
||||||
// 计算 固定文本segment 的 数量 和 文本总长度
|
// 计算 固定文本segment 的 数量 和 文本总长度
|
||||||
int literalSegmentSize = 0, fixedTextTotalLength = 0;
|
int literalSegmentSize = 0, fixedTextTotalLength = 0;
|
||||||
@ -612,9 +615,9 @@ public abstract class StrTemplate {
|
|||||||
// 获取 占位符segment 列表
|
// 获取 占位符segment 列表
|
||||||
final int placeholderSegmentsSize = segments.size() - literalSegmentSize;
|
final int placeholderSegmentsSize = segments.size() - literalSegmentSize;
|
||||||
if (placeholderSegmentsSize == 0) {
|
if (placeholderSegmentsSize == 0) {
|
||||||
this.placeholderSegments = ListUtil.zero();
|
this.placeholderSegments = Collections.emptyList();
|
||||||
} else {
|
} else {
|
||||||
List<AbstractPlaceholderSegment> placeholderSegments = new ArrayList<>(placeholderSegmentsSize);
|
final List<AbstractPlaceholderSegment> placeholderSegments = new ArrayList<>(placeholderSegmentsSize);
|
||||||
for (StrTemplateSegment segment : segments) {
|
for (StrTemplateSegment segment : segments) {
|
||||||
if (segment instanceof AbstractPlaceholderSegment) {
|
if (segment instanceof AbstractPlaceholderSegment) {
|
||||||
placeholderSegments.add((AbstractPlaceholderSegment) segment);
|
placeholderSegments.add((AbstractPlaceholderSegment) segment);
|
||||||
@ -624,6 +627,26 @@ public abstract class StrTemplate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加 固定文本segment,过滤 空字符串 并 合并相邻的固定文本
|
||||||
|
*
|
||||||
|
* @param isLastLiteralSegment 上一个新增的segment是否是固定文本
|
||||||
|
* @param list 已保存的segment列表
|
||||||
|
* @param newText 新的固定文本
|
||||||
|
*/
|
||||||
|
protected void addLiteralSegment(boolean isLastLiteralSegment, List<StrTemplateSegment> list, String newText) {
|
||||||
|
if (newText.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isLastLiteralSegment) {
|
||||||
|
// 最后的固定文本segment 和 新固定文本 合并为一个
|
||||||
|
int lastIdx = list.size() - 1;
|
||||||
|
StrTemplateSegment lastLiteralSegment = list.get(lastIdx);
|
||||||
|
list.set(lastIdx, new LiteralSegment(lastLiteralSegment.getText() + newText));
|
||||||
|
} else {
|
||||||
|
list.add(new LiteralSegment(newText));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 模板 解析为 Segment 列表
|
* 将 模板 解析为 Segment 列表
|
||||||
@ -651,45 +674,6 @@ public abstract class StrTemplate {
|
|||||||
return placeholderSegments;
|
return placeholderSegments;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 优化节点列表
|
|
||||||
* <p>移除空文本节点,合并连续的文本节点</p>
|
|
||||||
*
|
|
||||||
* @param segments 节点列表
|
|
||||||
* @return 不占用多余空间的节点列表
|
|
||||||
*/
|
|
||||||
private List<StrTemplateSegment> optimizeSegments(final List<StrTemplateSegment> segments) {
|
|
||||||
if (CollUtil.isEmpty(segments)) {
|
|
||||||
return segments;
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<StrTemplateSegment> list = new ArrayList<>(segments.size());
|
|
||||||
StrTemplateSegment last;
|
|
||||||
for (StrTemplateSegment segment : segments) {
|
|
||||||
if (segment instanceof LiteralSegment) {
|
|
||||||
// 空的文本节点,没有任何意义
|
|
||||||
if (segment.getText().isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (list.isEmpty()) {
|
|
||||||
list.add(segment);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
last = list.get(list.size() - 1);
|
|
||||||
// 如果是两个连续的文本节点,需要合并
|
|
||||||
if (last instanceof LiteralSegment) {
|
|
||||||
list.set(list.size() - 1, new LiteralSegment(last.getText() + segment.getText()));
|
|
||||||
} else {
|
|
||||||
list.add(segment);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
list.add(segment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 释放空闲的列表元素
|
|
||||||
return list.size() == segments.size() ? list : new ArrayList<>(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 抽象Builder
|
* 抽象Builder
|
||||||
*
|
*
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package org.dromara.hutool.core.text.placeholder.segment;
|
package org.dromara.hutool.core.text.placeholder.segment;
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字符串模板-占位符-抽象 Segment
|
* 字符串模板-占位符-抽象 Segment
|
||||||
* <p>例如:{@literal "???"->"???", "{}"->"{}", "{name}"->"name"}</p>
|
* <p>例如:{@literal "???"->"???", "{}"->"{}", "{name}"->"name"}</p>
|
||||||
@ -25,14 +23,6 @@ public abstract class AbstractPlaceholderSegment implements StrTemplateSegment {
|
|||||||
return placeholder;
|
return placeholder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void format(final StringBuilder sb, final Iterator<String> valueIterator) {
|
|
||||||
// 当前是 占位符,直接 替换为 参数值
|
|
||||||
if (valueIterator.hasNext()) {
|
|
||||||
sb.append(valueIterator.next());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPlaceholder() {
|
public String getPlaceholder() {
|
||||||
return placeholder;
|
return placeholder;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package org.dromara.hutool.core.text.placeholder.segment;
|
package org.dromara.hutool.core.text.placeholder.segment;
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字符串模板-固定文本 Segment
|
* 字符串模板-固定文本 Segment
|
||||||
*
|
*
|
||||||
@ -23,10 +21,4 @@ public class LiteralSegment implements StrTemplateSegment {
|
|||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void format(final StringBuilder sb, final Iterator<String> valueIterator) {
|
|
||||||
// 在格式化中 拼接 固定文本
|
|
||||||
sb.append(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package org.dromara.hutool.core.text.placeholder.segment;
|
package org.dromara.hutool.core.text.placeholder.segment;
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字符串模板-抽象 Segment
|
* 字符串模板-抽象 Segment
|
||||||
*
|
*
|
||||||
@ -9,16 +7,6 @@ import java.util.Iterator;
|
|||||||
* @since 6.0.0
|
* @since 6.0.0
|
||||||
*/
|
*/
|
||||||
public interface StrTemplateSegment {
|
public interface StrTemplateSegment {
|
||||||
/**
|
|
||||||
* 在格式化中,按顺序 拼接 参数值
|
|
||||||
*
|
|
||||||
* <p>如果是固定文本,则直接拼接,如果是占位符,则拼接参数值</p>
|
|
||||||
*
|
|
||||||
* @param sb 存储格式化结果的变量
|
|
||||||
* @param valueIterator 与占位符依次对应的参数值列表
|
|
||||||
*/
|
|
||||||
void format(final StringBuilder sb, final Iterator<String> valueIterator);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取文本值
|
* 获取文本值
|
||||||
*
|
*
|
||||||
|
@ -93,6 +93,8 @@ public class NamedPlaceholderStrTemplate extends StrTemplate {
|
|||||||
String variableName;
|
String variableName;
|
||||||
// 完整的占位符
|
// 完整的占位符
|
||||||
String wholePlaceholder;
|
String wholePlaceholder;
|
||||||
|
// 上一个解析的segment是否是固定文本,如果是,则需要和当前新的文本部分合并
|
||||||
|
boolean isLastLiteralSegment = false;
|
||||||
while (openCursor > -1) {
|
while (openCursor > -1) {
|
||||||
// 开始符号是否被转义,若是则跳过,并寻找下一个开始符号
|
// 开始符号是否被转义,若是则跳过,并寻找下一个开始符号
|
||||||
if (openCursor > 0 && src[openCursor - 1] == escape) {
|
if (openCursor > 0 && src[openCursor - 1] == escape) {
|
||||||
@ -101,9 +103,8 @@ public class NamedPlaceholderStrTemplate extends StrTemplate {
|
|||||||
hasDoubleEscape = true;
|
hasDoubleEscape = true;
|
||||||
} else {
|
} else {
|
||||||
// 开始符号被转义,跳过,寻找下一个开始符号
|
// 开始符号被转义,跳过,寻找下一个开始符号
|
||||||
segments.add(new LiteralSegment(
|
addLiteralSegment(isLastLiteralSegment, segments, template.substring(closeCursor, openCursor - 1) + prefix);
|
||||||
template.substring(closeCursor, openCursor - 1) + prefix
|
isLastLiteralSegment = true;
|
||||||
));
|
|
||||||
closeCursor = openCursor + openLength;
|
closeCursor = openCursor + openLength;
|
||||||
openCursor = template.indexOf(prefix, closeCursor);
|
openCursor = template.indexOf(prefix, closeCursor);
|
||||||
continue;
|
continue;
|
||||||
@ -114,12 +115,12 @@ public class NamedPlaceholderStrTemplate extends StrTemplate {
|
|||||||
if (!hasDoubleEscape) {
|
if (!hasDoubleEscape) {
|
||||||
if (closeCursor < openCursor) {
|
if (closeCursor < openCursor) {
|
||||||
// 完整记录当前占位符的开始符号与上一占位符的结束符号间的字符串
|
// 完整记录当前占位符的开始符号与上一占位符的结束符号间的字符串
|
||||||
segments.add(new LiteralSegment(template.substring(closeCursor, openCursor)));
|
addLiteralSegment(isLastLiteralSegment, segments, template.substring(closeCursor, openCursor));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 存在双转义符,只能保留一个转义符
|
// 存在双转义符,只能保留一个转义符
|
||||||
hasDoubleEscape = false;
|
hasDoubleEscape = false;
|
||||||
segments.add(new LiteralSegment(template.substring(closeCursor, openCursor - 1)));
|
addLiteralSegment(isLastLiteralSegment, segments, template.substring(closeCursor, openCursor - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置结束游标至当前占位符的开始处
|
// 重置结束游标至当前占位符的开始处
|
||||||
@ -166,6 +167,7 @@ public class NamedPlaceholderStrTemplate extends StrTemplate {
|
|||||||
// 当作变量名称处理
|
// 当作变量名称处理
|
||||||
segments.add(new NamedPlaceholderSegment(variableName, wholePlaceholder));
|
segments.add(new NamedPlaceholderSegment(variableName, wholePlaceholder));
|
||||||
}
|
}
|
||||||
|
isLastLiteralSegment = false;
|
||||||
// 完成当前占位符的处理匹配,寻找下一个
|
// 完成当前占位符的处理匹配,寻找下一个
|
||||||
closeCursor = end + closeLength;
|
closeCursor = end + closeLength;
|
||||||
}
|
}
|
||||||
@ -176,7 +178,7 @@ public class NamedPlaceholderStrTemplate extends StrTemplate {
|
|||||||
|
|
||||||
// 若匹配结束后仍有未处理的字符串,则直接将其拼接到表达式上
|
// 若匹配结束后仍有未处理的字符串,则直接将其拼接到表达式上
|
||||||
if (closeCursor < src.length) {
|
if (closeCursor < src.length) {
|
||||||
segments.add(new LiteralSegment(template.substring(closeCursor, src.length)));
|
addLiteralSegment(isLastLiteralSegment, segments, template.substring(closeCursor));
|
||||||
}
|
}
|
||||||
return segments;
|
return segments;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,8 @@ public class SinglePlaceholderStrTemplate extends StrTemplate {
|
|||||||
int handledPosition = 0;
|
int handledPosition = 0;
|
||||||
// 占位符所在位置
|
// 占位符所在位置
|
||||||
int delimIndex;
|
int delimIndex;
|
||||||
|
// 上一个解析的segment是否是固定文本,如果是,则需要和当前新的文本部分合并
|
||||||
|
boolean lastIsLiteralSegment = false;
|
||||||
// 复用的占位符变量
|
// 复用的占位符变量
|
||||||
final SinglePlaceholderSegment singlePlaceholderSegment = SinglePlaceholderSegment.newInstance(placeholder);
|
final SinglePlaceholderSegment singlePlaceholderSegment = SinglePlaceholderSegment.newInstance(placeholder);
|
||||||
List<StrTemplateSegment> segments = null;
|
List<StrTemplateSegment> segments = null;
|
||||||
@ -63,7 +65,7 @@ public class SinglePlaceholderStrTemplate extends StrTemplate {
|
|||||||
}
|
}
|
||||||
// 字符串模板剩余部分不再包含占位符
|
// 字符串模板剩余部分不再包含占位符
|
||||||
if (handledPosition < strPatternLength) {
|
if (handledPosition < strPatternLength) {
|
||||||
segments.add(new LiteralSegment(template.substring(handledPosition, strPatternLength)));
|
addLiteralSegment(lastIsLiteralSegment, segments, template.substring(handledPosition));
|
||||||
}
|
}
|
||||||
return segments;
|
return segments;
|
||||||
} else if (segments == null) {
|
} else if (segments == null) {
|
||||||
@ -75,25 +77,25 @@ public class SinglePlaceholderStrTemplate extends StrTemplate {
|
|||||||
// 存在 双转义符
|
// 存在 双转义符
|
||||||
if (delimIndex > 1 && template.charAt(delimIndex - 2) == escape) {
|
if (delimIndex > 1 && template.charAt(delimIndex - 2) == escape) {
|
||||||
// 转义符之前还有一个转义符,形如:"//{",占位符依旧有效
|
// 转义符之前还有一个转义符,形如:"//{",占位符依旧有效
|
||||||
segments.add(new LiteralSegment(template.substring(handledPosition, delimIndex - 1)));
|
addLiteralSegment(lastIsLiteralSegment, segments, template.substring(handledPosition, delimIndex - 1));
|
||||||
segments.add(singlePlaceholderSegment);
|
segments.add(singlePlaceholderSegment);
|
||||||
|
lastIsLiteralSegment = false;
|
||||||
handledPosition = delimIndex + placeholderLength;
|
handledPosition = delimIndex + placeholderLength;
|
||||||
} else {
|
} else {
|
||||||
// 占位符被转义,形如:"/{",当前字符并不是一个真正的占位符,而是普通字符串的一部分
|
// 占位符被转义,形如:"/{",当前字符并不是一个真正的占位符,而是普通字符串的一部分
|
||||||
segments.add(new LiteralSegment(
|
addLiteralSegment(lastIsLiteralSegment, segments, template.substring(handledPosition, delimIndex - 1) + placeholder.charAt(0));
|
||||||
template.substring(handledPosition, delimIndex - 1) + placeholder.charAt(0)
|
lastIsLiteralSegment = true;
|
||||||
));
|
|
||||||
handledPosition = delimIndex + 1;
|
handledPosition = delimIndex + 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 正常占位符
|
// 正常占位符
|
||||||
segments.add(new LiteralSegment(template.substring(handledPosition, delimIndex)));
|
addLiteralSegment(lastIsLiteralSegment, segments, template.substring(handledPosition, delimIndex));
|
||||||
segments.add(singlePlaceholderSegment);
|
segments.add(singlePlaceholderSegment);
|
||||||
|
lastIsLiteralSegment = false;
|
||||||
handledPosition = delimIndex + placeholderLength;
|
handledPosition = delimIndex + placeholderLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// region 格式化方法
|
// region 格式化方法
|
||||||
// ################################################## 格式化方法 ##################################################
|
// ################################################## 格式化方法 ##################################################
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user