mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
添加一个占位符解析器
This commit is contained in:
parent
d799e43e54
commit
c4c11ffeb6
@ -0,0 +1,162 @@
|
|||||||
|
package cn.hutool.core.text;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>一个简单的占位符解析器。给定占位符的左右边界符号以及转义符,
|
||||||
|
* 将允许把一段字符串中的占位符解析并替换为指定内容,支持指定转义符对边界符号进行转义。<br>
|
||||||
|
* 比如:
|
||||||
|
* <pre>{@code
|
||||||
|
* String text = "select * from #[tableName] where id = #[id]";
|
||||||
|
* PlaceholderParser parser = new PlaceholderParser(str -> "?", "#[", "]");
|
||||||
|
* parser.apply(text); // = select * from ? where id = ?
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @author huangchengxing
|
||||||
|
*/
|
||||||
|
public class PlaceholderParser implements UnaryOperator<String> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* processor
|
||||||
|
*/
|
||||||
|
private final UnaryOperator<String> processor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 占位符开始符号
|
||||||
|
*/
|
||||||
|
private final String open;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束符号长度
|
||||||
|
*/
|
||||||
|
private final int openLength;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 占位符结束符号
|
||||||
|
*/
|
||||||
|
private final String close;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束符号长度
|
||||||
|
*/
|
||||||
|
private final int closeLength;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转义符
|
||||||
|
*/
|
||||||
|
private final char escape;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个占位符解析器
|
||||||
|
*
|
||||||
|
* @param processor 占位符处理器
|
||||||
|
* @param open 占位符开始符号,不允许为空
|
||||||
|
* @param close 占位符结束符号,不允许为空
|
||||||
|
* @param escape 转义符
|
||||||
|
*/
|
||||||
|
public PlaceholderParser(UnaryOperator<String> processor, String open, String close, char escape) {
|
||||||
|
Assert.isFalse(StrChecker.isEmpty(open), "开始符号不能为空");
|
||||||
|
Assert.isFalse(StrChecker.isEmpty(close), "结束符号不能为空");
|
||||||
|
this.processor = processor;
|
||||||
|
this.open = open;
|
||||||
|
this.openLength = open.length();
|
||||||
|
this.close = close;
|
||||||
|
this.closeLength = close.length();
|
||||||
|
this.escape = escape;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个占位符解析器,默认转义符为{@code "\"}
|
||||||
|
*
|
||||||
|
* @param processor 占位符处理器
|
||||||
|
* @param open 占位符开始符号,不允许为空
|
||||||
|
* @param close 占位符结束符号,不允许为空
|
||||||
|
*/
|
||||||
|
public PlaceholderParser(UnaryOperator<String> processor, String open, String close) {
|
||||||
|
this(processor, open, close, '\\');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析并替换字符串中的占位符
|
||||||
|
*
|
||||||
|
* @param text 待解析的字符串
|
||||||
|
* @return 处理后的字符串
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String apply(String text) {
|
||||||
|
Objects.requireNonNull(processor);
|
||||||
|
if (StrChecker.isEmpty(text)) {
|
||||||
|
return StrChecker.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 寻找第一个开始符号
|
||||||
|
int closeCursor = 0;
|
||||||
|
int openCursor = text.indexOf(open, closeCursor);
|
||||||
|
if (openCursor == -1) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始匹配
|
||||||
|
char[] src = text.toCharArray();
|
||||||
|
final StringBuilder result = new StringBuilder();
|
||||||
|
StringBuilder expression = new StringBuilder();
|
||||||
|
while (openCursor > -1) {
|
||||||
|
|
||||||
|
// 开始符号是否被转义,若是则跳过并寻找下一个开始符号
|
||||||
|
if (openCursor > 0 && src[openCursor - 1] == escape) {
|
||||||
|
result.append(src, closeCursor, openCursor - closeCursor - 1).append(open);
|
||||||
|
closeCursor = openCursor + openLength;
|
||||||
|
openCursor = text.indexOf(open, closeCursor);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录当前位符的开始符号与上一占位符的结束符号间的字符串
|
||||||
|
result.append(src, closeCursor, openCursor - closeCursor);
|
||||||
|
|
||||||
|
// 重置结束游标至当前占位符的开始处
|
||||||
|
closeCursor = openCursor + openLength;
|
||||||
|
|
||||||
|
// 寻找结束符号下标
|
||||||
|
int end = text.indexOf(close, closeCursor);
|
||||||
|
while (end > -1) {
|
||||||
|
// 结束符号被转义,寻找下一个结束符号
|
||||||
|
if (end > closeCursor && src[end - 1] == escape) {
|
||||||
|
expression.append(src, closeCursor, end - closeCursor - 1).append(close);
|
||||||
|
closeCursor = end + closeLength;
|
||||||
|
end = text.indexOf(close, closeCursor);
|
||||||
|
}
|
||||||
|
// 找到结束符号
|
||||||
|
else {
|
||||||
|
expression.append(src, closeCursor, end - closeCursor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 未能找到结束符号,说明匹配结束
|
||||||
|
if (end == -1) {
|
||||||
|
result.append(src, openCursor, src.length - openCursor);
|
||||||
|
closeCursor = src.length;
|
||||||
|
}
|
||||||
|
// 找到结束符号,将开始到结束符号之间的字符串替换为指定表达式
|
||||||
|
else {
|
||||||
|
result.append(processor.apply(expression.toString()));
|
||||||
|
expression = new StringBuilder();
|
||||||
|
// 完成当前占位符的处理匹配,寻找下一个
|
||||||
|
closeCursor = end + close.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 寻找下一个开始符号
|
||||||
|
openCursor = text.indexOf(open, closeCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 若匹配结束后仍有未处理的字符串,则直接将其拼接到表达式上
|
||||||
|
if (closeCursor < src.length) {
|
||||||
|
result.append(src, closeCursor, src.length - closeCursor);
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package cn.hutool.core.text;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test for {@link PlaceholderParser}
|
||||||
|
*
|
||||||
|
* @author huangchengxing
|
||||||
|
*/
|
||||||
|
public class PlaceholderParserTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParse() {
|
||||||
|
String text = "i {a}{m} a {jvav} programmer";
|
||||||
|
PlaceholderParser parser = new PlaceholderParser(str -> str, "{", "}");
|
||||||
|
Assert.assertEquals(
|
||||||
|
"i am a jvav programmer",
|
||||||
|
parser.apply(text)
|
||||||
|
);
|
||||||
|
|
||||||
|
text = "i [a][m] a [jvav] programmer";
|
||||||
|
parser = new PlaceholderParser(str -> str, "[", "]");
|
||||||
|
Assert.assertEquals(
|
||||||
|
"i am a jvav programmer",
|
||||||
|
parser.apply(text)
|
||||||
|
);
|
||||||
|
|
||||||
|
text = "i \\[a][[m\\]] a [jvav] programmer";
|
||||||
|
parser = new PlaceholderParser(str -> str, "[", "]");
|
||||||
|
Assert.assertEquals(
|
||||||
|
"i [a][m] a jvav programmer",
|
||||||
|
parser.apply(text)
|
||||||
|
);
|
||||||
|
|
||||||
|
text = "i /[a][[m/]] a [jvav] programmer";
|
||||||
|
parser = new PlaceholderParser(str -> str, "[", "]", '/');
|
||||||
|
Assert.assertEquals(
|
||||||
|
"i [a][m] a jvav programmer",
|
||||||
|
parser.apply(text)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user