From c4c11ffeb64460dd9ab5f6fbefa8031c06a8459f Mon Sep 17 00:00:00 2001
From: huangchengxing <841396397@qq.com>
Date: Tue, 8 Nov 2022 09:24:05 +0800
Subject: [PATCH 1/4] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=B8=80=E4=B8=AA?=
=?UTF-8?q?=E5=8D=A0=E4=BD=8D=E7=AC=A6=E8=A7=A3=E6=9E=90=E5=99=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../hutool/core/text/PlaceholderParser.java | 162 ++++++++++++++++++
.../core/text/PlaceholderParserTest.java | 44 +++++
2 files changed, 206 insertions(+)
create mode 100644 hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java
create mode 100644 hutool-core/src/test/java/cn/hutool/core/text/PlaceholderParserTest.java
diff --git a/hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java b/hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java
new file mode 100644
index 000000000..50ec2a4f3
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java
@@ -0,0 +1,162 @@
+package cn.hutool.core.text;
+
+import cn.hutool.core.lang.Assert;
+
+import java.util.Objects;
+import java.util.function.UnaryOperator;
+
+/**
+ *
一个简单的占位符解析器。给定占位符的左右边界符号以及转义符,
+ * 将允许把一段字符串中的占位符解析并替换为指定内容,支持指定转义符对边界符号进行转义。
+ * 比如:
+ *
{@code
+ * String text = "select * from #[tableName] where id = #[id]";
+ * PlaceholderParser parser = new PlaceholderParser(str -> "?", "#[", "]");
+ * parser.apply(text); // = select * from ? where id = ?
+ * }
+ *
+ * @author huangchengxing
+ */
+public class PlaceholderParser implements UnaryOperator {
+
+ /**
+ * processor
+ */
+ private final UnaryOperator 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 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 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();
+ }
+
+}
diff --git a/hutool-core/src/test/java/cn/hutool/core/text/PlaceholderParserTest.java b/hutool-core/src/test/java/cn/hutool/core/text/PlaceholderParserTest.java
new file mode 100644
index 000000000..bb7b7a3de
--- /dev/null
+++ b/hutool-core/src/test/java/cn/hutool/core/text/PlaceholderParserTest.java
@@ -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)
+ );
+ }
+
+}
From 0eb1ecb1b7111d221d1ac4f80d20ed5a811ec447 Mon Sep 17 00:00:00 2001
From: huangchengxing <841396397@qq.com>
Date: Tue, 8 Nov 2022 18:09:43 +0800
Subject: [PATCH 2/4] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=A4=84=E7=90=86?=
=?UTF-8?q?=E5=99=A8=E9=9D=9E=E7=A9=BA=E6=A0=A1=E9=AA=8C=E6=97=B6=E6=9C=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/cn/hutool/core/text/PlaceholderParser.java | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java b/hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java
index 50ec2a4f3..c01cd6116 100644
--- a/hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java
+++ b/hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java
@@ -57,10 +57,11 @@ public class PlaceholderParser implements UnaryOperator {
* @param close 占位符结束符号,不允许为空
* @param escape 转义符
*/
- public PlaceholderParser(UnaryOperator processor, String open, String close, char escape) {
+ public PlaceholderParser(
+ final UnaryOperator processor, final String open, final String close, final char escape) {
Assert.isFalse(StrChecker.isEmpty(open), "开始符号不能为空");
Assert.isFalse(StrChecker.isEmpty(close), "结束符号不能为空");
- this.processor = processor;
+ this.processor = Objects.requireNonNull(processor);
this.open = open;
this.openLength = open.length();
this.close = close;
@@ -75,7 +76,8 @@ public class PlaceholderParser implements UnaryOperator {
* @param open 占位符开始符号,不允许为空
* @param close 占位符结束符号,不允许为空
*/
- public PlaceholderParser(UnaryOperator processor, String open, String close) {
+ public PlaceholderParser(
+ final UnaryOperator processor, final String open, final String close) {
this(processor, open, close, '\\');
}
@@ -86,8 +88,7 @@ public class PlaceholderParser implements UnaryOperator {
* @return 处理后的字符串
*/
@Override
- public String apply(String text) {
- Objects.requireNonNull(processor);
+ public String apply(final String text) {
if (StrChecker.isEmpty(text)) {
return StrChecker.EMPTY;
}
From 1d25cbdd243ea2321fd0aaec3a915b51926e1109 Mon Sep 17 00:00:00 2001
From: Zjp <1215582715@qq.com>
Date: Wed, 9 Nov 2022 11:12:46 +0800
Subject: [PATCH 3/4] =?UTF-8?q?1.=20=E4=BC=98=E5=8C=96=E4=BA=86=E4=BF=9D?=
=?UTF-8?q?=E5=AD=98=E7=BB=93=E6=9E=9C=E7=9A=84StringBuilder=E7=9A=84?=
=?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E9=95=BF=E5=BA=A6;=202.=20=E4=BC=98?=
=?UTF-8?q?=E5=8C=96=E4=BA=86expression=E7=9A=84=E9=87=8D=E7=BD=AE?=
=?UTF-8?q?=E6=93=8D=E4=BD=9C;=203.=20=E4=BC=98=E5=8C=96=E4=BA=86=E8=A7=A3?=
=?UTF-8?q?=E6=9E=90=E5=BC=82=E5=B8=B8=E6=97=B6=E7=9A=84=E5=A4=84=E7=90=86?=
=?UTF-8?q?;?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/cn/hutool/core/text/PlaceholderParser.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java b/hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java
index c01cd6116..2d0aef5b6 100644
--- a/hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java
+++ b/hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java
@@ -1,5 +1,6 @@
package cn.hutool.core.text;
+import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Assert;
import java.util.Objects;
@@ -102,7 +103,7 @@ public class PlaceholderParser implements UnaryOperator {
// 开始匹配
char[] src = text.toCharArray();
- final StringBuilder result = new StringBuilder();
+ final StringBuilder result = new StringBuilder(src.length);
StringBuilder expression = new StringBuilder();
while (openCursor > -1) {
@@ -136,15 +137,14 @@ public class PlaceholderParser implements UnaryOperator {
}
}
- // 未能找到结束符号,说明匹配结束
+ // 未能找到结束符号,说明匹配异常
if (end == -1) {
- result.append(src, openCursor, src.length - openCursor);
- closeCursor = src.length;
+ throw new UtilException("\"{}\" 中字符下标 {} 处的开始符没有找到对应的结束符", text, openCursor);
}
// 找到结束符号,将开始到结束符号之间的字符串替换为指定表达式
else {
result.append(processor.apply(expression.toString()));
- expression = new StringBuilder();
+ expression.setLength(0);
// 完成当前占位符的处理匹配,寻找下一个
closeCursor = end + close.length();
}
From 20d71d0e495fef0fefe19cff250b43eacc09b3c8 Mon Sep 17 00:00:00 2001
From: Zjp <1215582715@qq.com>
Date: Wed, 9 Nov 2022 15:24:07 +0800
Subject: [PATCH 4/4] add @author;
---
.../src/main/java/cn/hutool/core/text/PlaceholderParser.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java b/hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java
index 2d0aef5b6..81c441cb4 100644
--- a/hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java
+++ b/hutool-core/src/main/java/cn/hutool/core/text/PlaceholderParser.java
@@ -17,6 +17,7 @@ import java.util.function.UnaryOperator;
* }
*
* @author huangchengxing
+ * @author emptypoint
*/
public class PlaceholderParser implements UnaryOperator {