目录
[一、QLExpress 中的字符串模型与语义定位](#一、QLExpress 中的字符串模型与语义定位)
[(二)+ 运算符的动态分派机制](#(二)+ 运算符的动态分派机制)
[1. 基本拼接:表达式级字符串构造](#1. 基本拼接:表达式级字符串构造)
[2. 条件拼接:字符串即业务判断结果](#2. 条件拼接:字符串即业务判断结果)
[3. 循环拼接:构建动态文本结构](#3. 循环拼接:构建动态文本结构)
[1. QLExpress 的格式化哲学](#1. QLExpress 的格式化哲学)
[2. 数值格式化的常用模式](#2. 数值格式化的常用模式)
[3. 千分位与补零的表达式实现](#3. 千分位与补零的表达式实现)
[1. 空值、空串、空白的标准写法](#1. 空值、空串、空白的标准写法)
[2. 长度与格式验证](#2. 长度与格式验证)
[3. 内容验证与弱正则策略](#3. 内容验证与弱正则策略)
[4. 综合校验:字符串即校验报告](#4. 综合校验:字符串即校验报告)
[1. 清理与规范化](#1. 清理与规范化)
[2. 分割、重组与抽取](#2. 分割、重组与抽取)
[3. 子串提取与定位](#3. 子串提取与定位)
[4. 字符统计与中英文处理](#4. 字符统计与中英文处理)
[(一)适合放在 QLExpress 的字符串逻辑](#(一)适合放在 QLExpress 的字符串逻辑)
[(二)不适合放在 QLExpress 的场景](#(二)不适合放在 QLExpress 的场景)
干货分享,感谢您的阅读!
在绝大多数业务系统中,字符串逻辑几乎无处不在:规则命中说明、校验失败原因、动态标签拼接、策略结果描述、配置化文本生成......
这些看似"简单"的字符串操作,往往正是规则系统中最频繁、最容易失控、也最容易被低估的一类逻辑。
在很多团队的实践中,一旦字符串处理能力不足,规则脚本就会迅速演变为"半成品程序":
要么依赖大量 Java 扩展函数,要么在规则中堆叠复杂的模板与正则,最终导致规则可读性下降、维护成本上升、线上风险放大。
QLExpress 在这方面的设计取向非常明确:不引入复杂模板机制,但提供足够强的表达式级字符串能力,让字符串自然融入规则语义本身。
字符串在 QLExpress 中不是"被动拼接的文本",而是:
-
可以参与运算符分派的基础类型
-
可以承载业务判断结果的表达式输出
-
可以在循环与条件中逐步构建的动态结构
-
可以直接作为规则执行结果返回给上层系统
正是基于这种定位,QLExpress 的字符串能力在规则引擎、风控系统、审核策略、动态配置等场景中表现出极强的工程适配性。
我们将围绕 QLExpress 的字符串能力,从表达式语义、执行模型、常见操作模式、复杂处理技巧以及工程实践边界五个层面展开,结合完整可运行示例,系统性地展示如何在真实业务中正确、稳定、高效地使用 QLExpress 处理字符串逻辑。

一、QLExpress 中的字符串模型与语义定位
(一)字符串是"表达式层"的基础类型
在 QLExpress 中:
-
字符串字面量使用单引号
'text' -
字符串变量来自
Context -
字符串与数值、布尔、对象可直接混合运算
-
+运算符在运行期具备动态重载语义
这意味着:
字符串并不是"模板替换工具",而是参与运算的核心数据类型。
(二)+ 运算符的动态分派机制
QLExpress 在执行阶段,会根据左右操作数的运行时类型决定行为:
| 场景 | 行为 |
|---|---|
| 任一操作数为 String | 执行字符串拼接 |
| 均为数值类型 | 执行数值运算 |
| 混合对象 | 调用 toString() |
因此以下写法在 QLExpress 中是天然成立的:
java
'年龄:' + age '年薪:' + salary * 12
这也是 QLExpress 非常适合业务表达式而非纯计算规则的重要原因。
(三)案例展示
我这里给出的 StringOperationsDemo 具体代码演示如下:
java
package org.zyf.javabasic.qlexpress.basic.strings;
import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;
/**
* @program: zyfboot-javabasic
* @description: QLExpress字符串操作演示 - 全面展示字符串处理和操作技巧
* @author: zhangyanfeng
* @create: 2025-12-25 23:50
**/
public class StringOperationsDemo {
private ExpressRunner runner;
public StringOperationsDemo() {
this.runner = new ExpressRunner();
System.out.println("✅ QLExpress字符串操作演示引擎初始化完成");
}
/**
* 演示字符串拼接操作
*/
public void demonstrateStringConcatenation() {
System.out.println("\n=== QLExpress字符串拼接演示 ===\n");
try {
DefaultContext<String, Object> context = new DefaultContext<>();
// 准备测试数据
context.put("firstName", "张");
context.put("lastName", "彦峰");
context.put("age", 30);
context.put("city", "北京");
context.put("salary", 15000.50);
// 1. 基本字符串拼接
System.out.println("🔗 1. 基本字符串拼接演示:");
Object concat1 = runner.execute("firstName + lastName", context, null, true, false);
Object concat2 = runner.execute("'姓名:' + firstName + lastName", context, null, true, false);
Object concat3 = runner.execute("firstName + lastName + ',年龄:' + age", context, null, true, false);
System.out.printf(" firstName + lastName = %s%n", concat1);
System.out.printf(" '姓名:' + firstName + lastName = %s%n", concat2);
System.out.printf(" firstName + lastName + ',年龄:' + age = %s%n%n", concat3);
// 2. 复杂字符串拼接
System.out.println("🎯 2. 复杂字符串拼接演示:");
Object complex1 = runner.execute("'员工信息:' + firstName + lastName + '(' + age + '岁),居住在' + city", context, null, true, false);
Object complex2 = runner.execute("'薪资:¥' + salary + '元/月,年薪:¥' + (salary * 12) + '元'", context, null, true, false);
System.out.printf(" 员工基本信息: %s%n", complex1);
System.out.printf(" 薪资信息: %s%n%n", complex2);
// 3. 条件拼接
System.out.println("❓ 3. 条件拼接演示:");
Object conditional1 = runner.execute("firstName + lastName + (age >= 18 ? '(成年)' : '(未成年)')", context, null, true, false);
Object conditional2 = runner.execute("'居住地:' + (city != null ? city : '未知')", context, null, true, false);
System.out.printf(" 条件年龄拼接: %s%n", conditional1);
System.out.printf(" 条件城市拼接: %s%n%n", conditional2);
// 4. 循环拼接
System.out.println("🔄 4. 循环拼接演示:");
String loopScript =
"result = '';" +
"for (i = 1; i <= 5; i++) {" +
" if (i > 1) result = result + ', ';" +
" result = result + '第' + i + '项';" +
"}" +
"return result;";
Object loopResult = runner.execute(loopScript, context, null, true, false);
System.out.printf(" 循环拼接结果: %s%n%n", loopResult);
} catch (Exception e) {
System.err.println("❌ 字符串拼接演示失败: " + e.getMessage());
e.printStackTrace();
}
}
/**
* 演示字符串格式化操作
*/
public void demonstrateStringFormatting() {
System.out.println("\n=== QLExpress字符串格式化演示 ===\n");
try {
DefaultContext<String, Object> context = new DefaultContext<>();
// 准备测试数据
context.put("name", "张彦峰");
context.put("score", 85.678);
context.put("count", 1234);
context.put("ratio", 0.75);
// 1. 数字格式化
System.out.println("🔢 1. 数字格式化演示:");
Object formatScore = runner.execute("'分数:' + Math.round(score * 100) / 100.0", context, null, true, false);
Object formatPercent = runner.execute("'比例:' + Math.round(ratio * 10000) / 100.0 + '%'", context, null, true, false);
System.out.printf(" 保留两位小数: %s%n", formatScore);
System.out.printf(" 百分比格式: %s%n%n", formatPercent);
// 2. 数字补零格式化
System.out.println("0️⃣ 2. 数字补零格式化演示:");
String padZeroScript =
"num = 5;" +
"padded = num < 10 ? \"0\" + num : String.valueOf(num);" +
"return '编号:' + padded;";
Object padded = runner.execute(padZeroScript, context, null, true, false);
System.out.printf(" 补零格式化: %s%n%n", padded);
// 3. 千分位格式化(简单实现)
System.out.println("💰 3. 千分位格式化演示:");
String thousandScript =
"numStr = String.valueOf(count);" +
"len = numStr.length();" +
"result = '';" +
"for (i = 0; i < len; i++) {" +
" if (i > 0 && (len - i) % 3 == 0) {" +
" result = result + ',';" +
" }" +
" result = result + numStr.charAt(i);" +
"}" +
"return '金额:¥' + result;";
Object thousand = runner.execute(thousandScript, context, null, true, false);
System.out.printf(" 千分位格式: %s%n%n", thousand);
// 4. 字符串模板格式化
System.out.println("📝 4. 字符串模板演示:");
System.out.println(" 模板演示已跳过");
} catch (Exception e) {
System.err.println("❌ 字符串格式化演示失败: " + e.getMessage());
e.printStackTrace();
}
}
/**
* 演示字符串验证操作
*/
public void demonstrateStringValidation() {
System.out.println("\n=== QLExpress字符串验证演示 ===\n");
try {
DefaultContext<String, Object> context = new DefaultContext<>();
// 准备测试数据
context.put("email", "zhangyanfeng@example.com");
context.put("phone", "13812345678");
context.put("idCard", "110101199001011234");
context.put("password", "Abc123456!");
context.put("emptyStr", "");
context.put("nullStr", null);
context.put("spaceStr", " ");
// 1. 基本验证
System.out.println("✅ 1. 基本字符串验证演示:");
Object isEmpty1 = runner.execute("emptyStr == null || emptyStr.length() == 0", context, null, true, false);
Object isEmpty2 = runner.execute("nullStr == null", context, null, true, false);
Object isBlank = runner.execute("spaceStr.trim().length() == 0", context, null, true, false);
System.out.printf(" 空字符串检查: %s%n", isEmpty1);
System.out.printf(" null字符串检查: %s%n", isEmpty2);
System.out.printf(" 空白字符串检查: %s%n%n", isBlank);
// 2. 长度验证
System.out.println("📏 2. 字符串长度验证演示:");
Object phoneLength = runner.execute("phone.length() == 11", context, null, true, false);
Object passwordLength = runner.execute("password.length() >= 8 && password.length() <= 20", context, null, true, false);
Object idCardLength = runner.execute("idCard.length() == 18", context, null, true, false);
System.out.printf(" 手机号长度验证: phone=%s, 长度正确=%s%n", context.get("phone"), phoneLength);
System.out.printf(" 密码长度验证: 长度合规=%s%n", passwordLength);
System.out.printf(" 身份证长度验证: 长度正确=%s%n%n", idCardLength);
// 3. 格式验证
System.out.println("🎯 3. 字符串格式验证演示:");
Object emailFormat = runner.execute("email.contains(\"@\") && email.contains(\".\")", context, null, true, false);
Object phoneFormat = runner.execute("phone.startsWith(\"1\") && phone.length() == 11", context, null, true, false);
System.out.printf(" 邮箱格式验证: email=%s, 格式正确=%s%n", context.get("email"), emailFormat);
System.out.printf(" 手机号格式验证: 格式正确=%s%n%n", phoneFormat);
// 4. 内容验证
System.out.println("🔍 4. 字符串内容验证演示:");
Object hasUpperCase = runner.execute("!password.equals(password.toLowerCase())", context, null, true, false);
Object hasLowerCase = runner.execute("!password.equals(password.toUpperCase())", context, null, true, false);
Object hasDigit = runner.execute("password.replaceAll(\"[^0-9]\", \"\").length() > 0", context, null, true, false);
Object hasSpecial = runner.execute("password.replaceAll(\"[a-zA-Z0-9]\", \"\").length() > 0", context, null, true, false);
System.out.printf(" 密码包含大写字母: %s%n", hasUpperCase);
System.out.printf(" 密码包含小写字母: %s%n", hasLowerCase);
System.out.printf(" 密码包含数字: %s%n", hasDigit);
System.out.printf(" 密码包含特殊字符: %s%n%n", hasSpecial);
// 5. 综合验证
System.out.println("🏆 5. 综合验证演示:");
String validateScript =
"emailValid = email != null && email.contains(\"@\") && email.contains(\".\") && email.length() > 5;" +
"phoneValid = phone != null && phone.length() == 11 && phone.startsWith(\"1\");" +
"passwordValid = password != null && password.length() >= 8 && " +
" !password.equals(password.toLowerCase()) && " +
" !password.equals(password.toUpperCase()) && " +
" password.replaceAll(\"[^0-9]\", \"\").length() > 0;" +
"return \"邮箱:\" + (emailValid ? \"✓\" : \"✗\") + \" 手机:\" + (phoneValid ? \"✓\" : \"✗\") + \" 密码:\" + (passwordValid ? \"✓\" : \"✗\");";
Object validation = runner.execute(validateScript, context, null, true, false);
System.out.printf(" 综合验证结果: %s%n%n", validation);
} catch (Exception e) {
System.err.println("❌ 字符串验证演示失败: " + e.getMessage());
e.printStackTrace();
}
}
/**
* 演示字符串处理操作
*/
public void demonstrateStringProcessing() {
System.out.println("\n=== QLExpress字符串处理演示 ===\n");
try {
DefaultContext<String, Object> context = new DefaultContext<>();
// 准备测试数据
context.put("text", "Hello QLExpress World! 你好,QLExpress世界!");
context.put("messyText", " Hello World \n\t ");
context.put("mixedCase", "hElLo WoRlD");
context.put("csvData", "apple,banana,orange;grape|watermelon");
// 1. 字符串清理
System.out.println("🧹 1. 字符串清理演示:");
Object trimmed = runner.execute("messyText.trim()", context, null, true, false);
Object normalized = runner.execute("messyText.trim().replaceAll(\"\\\\s+\", \" \")", context, null, true, false);
Object cleaned = runner.execute("text.replaceAll(\"[!,]\", \"\")", context, null, true, false);
System.out.printf(" 原始文本: '%s'%n", context.get("messyText"));
System.out.printf(" 去除首尾空格: '%s'%n", trimmed);
System.out.printf(" 规范化空格: '%s'%n", normalized);
System.out.printf(" 清理标点符号: '%s'%n%n", cleaned);
// 2. 大小写转换
System.out.println("🔄 2. 大小写转换演示:");
Object upperCase = runner.execute("mixedCase.toUpperCase()", context, null, true, false);
Object lowerCase = runner.execute("mixedCase.toLowerCase()", context, null, true, false);
// 首字母大写
String capitalizeScript =
"str = mixedCase.toLowerCase();" +
"return str.substring(0, 1).toUpperCase() + str.substring(1);";
Object capitalized = runner.execute(capitalizeScript, context, null, true, false);
System.out.printf(" 原始文本: %s%n", context.get("mixedCase"));
System.out.printf(" 全部大写: %s%n", upperCase);
System.out.printf(" 全部小写: %s%n", lowerCase);
System.out.printf(" 首字母大写: %s%n%n", capitalized);
// 3. 字符串分割和重组
System.out.println("✂️ 3. 字符串分割和重组演示:");
String splitScript =
"parts1 = csvData.split(\",\");" +
"parts2 = csvData.split(\"[,;|]\");" +
"return \"按逗号分割: \" + parts1.length + \"个, 按多字符分割: \" + parts2.length + \"个\";";
Object splitResult = runner.execute(splitScript, context, null, true, false);
System.out.printf(" 分割结果: %s%n", splitResult);
String joinScript =
"words = text.split(\" \");" +
"result = \"\";" +
"for (i = 0; i < words.length; i++) {" +
" if (i > 0) result = result + \" | \";" +
" result = result + words[i];" +
"}" +
"return result;";
Object joinResult = runner.execute(joinScript, context, null, true, false);
System.out.printf(" 重新连接: %s%n%n", joinResult);
// 4. 字符串提取
System.out.println("🔍 4. 字符串提取演示:");
Object firstWord = runner.execute("text.substring(0, text.indexOf(\" \"))", context, null, true, false);
Object lastWord = runner.execute("text.substring(text.lastIndexOf(\" \") + 1)", context, null, true, false);
Object middlePart = runner.execute("text.substring(6, 15)", context, null, true, false);
System.out.printf(" 提取第一个单词: %s%n", firstWord);
System.out.printf(" 提取最后一个词: %s%n", lastWord);
System.out.printf(" 提取中间部分: %s%n%n", middlePart);
// 5. 字符统计
System.out.println("📊 5. 字符统计演示:");
String countScript =
"totalLength = text.length();" +
"englishCount = text.replaceAll(\"[^a-zA-Z]\", \"\").length();" +
"chineseCount = text.replaceAll(\"[^\\\\u4e00-\\\\u9fa5]\", \"\").length();" +
"spaceCount = text.replaceAll(\"[^ ]\", \"\").length();" +
"return \"总字符:\" + totalLength + \", 英文:\" + englishCount + \", 中文:\" + chineseCount + \", 空格:\" + spaceCount;";
Object countResult = runner.execute(countScript, context, null, true, false);
System.out.printf(" 字符统计: %s%n%n", countResult);
} catch (Exception e) {
System.err.println("❌ 字符串处理演示失败: " + e.getMessage());
e.printStackTrace();
}
}
/**
* 运行所有演示
*/
public void runAllDemonstrations() {
System.out.println("🚀 开始QLExpress字符串操作完整演示...\n");
demonstrateStringConcatenation();
demonstrateStringFormatting();
demonstrateStringValidation();
demonstrateStringProcessing();
System.out.println("✅ QLExpress字符串操作演示完成!");
System.out.println("\n📚 学习要点:");
System.out.println(" 1. 字符串拼接: 使用 + 操作符,支持与各种类型混合");
System.out.println(" 2. 字符串格式化: 数字格式化、模板替换、条件拼接");
System.out.println(" 3. 字符串验证: 长度检查、格式验证、内容验证");
System.out.println(" 4. 字符串处理: 清理、转换、分割、提取、统计");
System.out.println(" 5. 正则表达式: replaceAll方法支持正则表达式替换");
System.out.println(" 6. 中文处理: 支持中文字符的各种操作");
}
/**
* 主方法 - 运行演示
*/
public static void main(String[] args) {
StringOperationsDemo demo = new StringOperationsDemo();
demo.runAllDemonstrations();
}
}
基本运行验证如下:
python
✅ QLExpress字符串操作演示引擎初始化完成
🚀 开始QLExpress字符串操作完整演示...
=== QLExpress字符串拼接演示 ===
🔗 1. 基本字符串拼接演示:
firstName + lastName = 张彦峰
'姓名:' + firstName + lastName = 姓名:张彦峰
firstName + lastName + ',年龄:' + age = 张彦峰,年龄:30
🎯 2. 复杂字符串拼接演示:
员工基本信息: 员工信息:张彦峰(30岁),居住在北京
薪资信息: 薪资:¥15000.5元/月,年薪:¥180006.0元
❓ 3. 条件拼接演示:
条件年龄拼接: 张彦峰(成年)
条件城市拼接: 居住地:北京
🔄 4. 循环拼接演示:
循环拼接结果: 第1项, 第2项, 第3项, 第4项, 第5项
=== QLExpress字符串格式化演示 ===
🔢 1. 数字格式化演示:
保留两位小数: 分数:85.68
百分比格式: 比例:75.0%
0️⃣ 2. 数字补零格式化演示:
补零格式化: 编号:05
💰 3. 千分位格式化演示:
千分位格式: 金额:¥1,234
📝 4. 字符串模板演示:
模板演示已跳过
=== QLExpress字符串验证演示 ===
✅ 1. 基本字符串验证演示:
空字符串检查: true
null字符串检查: true
空白字符串检查: true
📏 2. 字符串长度验证演示:
手机号长度验证: phone=13812345678, 长度正确=true
密码长度验证: 长度合规=true
身份证长度验证: 长度正确=true
🎯 3. 字符串格式验证演示:
邮箱格式验证: email=zhangyanfeng@example.com, 格式正确=true
手机号格式验证: 格式正确=true
🔍 4. 字符串内容验证演示:
密码包含大写字母: true
密码包含小写字母: true
密码包含数字: true
密码包含特殊字符: true
🏆 5. 综合验证演示:
综合验证结果: 邮箱:✓ 手机:✓ 密码:✓
=== QLExpress字符串处理演示 ===
🧹 1. 字符串清理演示:
原始文本: ' Hello World
'
去除首尾空格: 'Hello World'
规范化空格: 'Hello World'
清理标点符号: 'Hello QLExpress World! 你好QLExpress世界'
🔄 2. 大小写转换演示:
原始文本: hElLo WoRlD
全部大写: HELLO WORLD
全部小写: hello world
首字母大写: Hello world
✂️ 3. 字符串分割和重组演示:
分割结果: 按逗号分割: 3个, 按多字符分割: 5个
重新连接: Hello | QLExpress | World! | 你好,QLExpress世界!
🔍 4. 字符串提取演示:
提取第一个单词: Hello
提取最后一个词: 你好,QLExpress世界!
提取中间部分: QLExpress
📊 5. 字符统计演示:
字符统计: 总字符:38, 英文:28, 中文:4, 空格:3
✅ QLExpress字符串操作演示完成!
📚 学习要点:
1. 字符串拼接: 使用 + 操作符,支持与各种类型混合
2. 字符串格式化: 数字格式化、模板替换、条件拼接
3. 字符串验证: 长度检查、格式验证、内容验证
4. 字符串处理: 清理、转换、分割、提取、统计
5. 正则表达式: replaceAll方法支持正则表达式替换
6. 中文处理: 支持中文字符的各种操作
Process finished with exit code 0
在代码中覆盖的场景包括:
-
拼接(Concatenation)
-
格式化(Formatting)
-
校验(Validation)
-
清洗 / 规范化(Processing)
-
分割与重组(Split & Join)
这正是规则工程中最典型的字符串生命周期。
二、各部分详细讲解和指导说明
(一)字符串拼接:从简单到复杂的表达能力
1. 基本拼接:表达式级字符串构造
QLExpress 的字符串拼接具有如下特征:
-
不依赖
StringBuilder -
不需要显式类型转换
-
表达式天然可读
java
firstName + lastName '姓名:' + firstName + lastName
推荐场景:
-
输出规则结果
-
动态提示信息
-
简单文本生成
2. 条件拼接:字符串即业务判断结果
借助三目表达式,字符串可以直接承载业务含义:
java
name + (age >= 18 ? '(成年)' : '(未成年)')
这是 QLExpress 在规则引擎、风控策略、审核逻辑中极为常见的写法:
-
表达式即结论
-
无需再写 if/else
3. 循环拼接:构建动态文本结构
QLExpress 支持完整的 for / if 语法,因此字符串可以在循环中逐步构建:
java
result = '';
for (i = 1; i <= 5; i++) {
if (i > 1) result = result + ', ';
result = result + '第' + i + '项';
}
return result;
工程意义:
-
可动态生成列表描述
-
可构造规则命中详情
-
避免 Java 侧重复封装逻辑
(二)字符串格式化:没有模板,但能力并不弱
1. QLExpress 的格式化哲学
QLExpress 并未内置类似 String.format 的模板引擎,其设计理念是:
用表达式而不是模板描述格式逻辑
这使得字符串格式化具备以下特征:
-
强逻辑可控
-
无隐式规则
-
可随业务变化自由扩展
2. 数值格式化的常用模式
保留小数位
java
Math.round(score * 100) / 100.0
百分比表示
java
Math.round(ratio * 10000) / 100.0 + '%'
这些写法虽然"原始",但:
-
可预测
-
易调试
-
不依赖额外函数注册
3. 千分位与补零的表达式实现
在没有格式化函数的情况下,通过字符串操作即可完成:
-
补零:三目 + 拼接
-
千分位:字符遍历 + 条件插入
这类写法非常适合:
-
金额展示
-
编号规则
-
报表字段
(三)字符串验证:规则引擎的天然适配点
1. 空值、空串、空白的标准写法
java
str == null
str.length() == 0
str.trim().length() == 0
这类判断在 QLExpress 中无需任何扩展,可直接使用 Java String API。
2. 长度与格式验证
典型验证逻辑:
java
phone.length() == 11
email.contains('@') && email.contains('.')
在规则系统中,这比正则更:
-
直观
-
易维护
-
可被非开发人员理解
3. 内容验证与弱正则策略
QLExpress 支持 replaceAll,从而实现"字符集合检测":
java
password.replaceAll('[^0-9]', '').length() > 0
这种方式的优势在于:
-
不依赖复杂正则
-
错误风险低
-
表达式可拆解
4. 综合校验:字符串即校验报告
QLExpress 非常适合返回"校验结果文本":
java
"邮箱:" + (emailValid ? "✓" : "✗")
在实际系统中,这种写法常用于:
-
表单规则校验
-
审核失败原因拼接
-
决策可解释性输出
(四)字符串处理:真正的"业务文本工具箱"
1. 清理与规范化
QLExpress 可直接调用:
-
trim -
replaceAll -
toUpperCase / toLowerCase
非常适合做:
-
用户输入清洗
-
日志内容标准化
-
文本归一处理
2. 分割、重组与抽取
字符串拆分在 QLExpress 中是一等能力:
java
csvData.split('[,;|]')
配合循环即可实现:
-
CSV 解析
-
多分隔符兼容
-
动态重组输出
3. 子串提取与定位
java
text.substring(0, text.indexOf(' '))
这类操作在以下场景非常常见:
-
协议字段解析
-
文本规则匹配
-
简单语义拆解
4. 字符统计与中英文处理
QLExpress 支持 Unicode 正则
java
text.replaceAll('[^\\u4e00-\\u9fa5]', '').length()
这使其可以胜任:
-
中英文混排统计
-
内容合规检测
-
文本质量评估
三、工程实践建议
(一)适合放在 QLExpress 的字符串逻辑
-
展示类文本拼接
-
规则解释性输出
-
校验与判断描述
-
可配置业务文案
(二)不适合放在 QLExpress 的场景
-
高性能大文本处理
-
复杂模板渲染(HTML / JSON)
-
超复杂正则解析
(三)最佳实践总结
-
让字符串表达业务含义,而不是技术细节
-
避免在表达式中写"不可读"的正则
-
复杂处理可拆为多个表达式变量
-
返回字符串结果,而不是状态码
四、结语
回顾全文可以看到,QLExpress 的字符串能力并不是简单意义上的"拼接 API 集合",而是一套与表达式执行模型深度绑定的业务建模工具。
通过对字符串拼接、格式化、校验、清理、分割、提取与统计等场景的系统演示,可以明确几个关键结论:
第一,字符串是 QLExpress 规则表达力的重要组成部分 。
借助 + 运算符的动态分派机制、三目表达式与完整控制流程,字符串可以直接承载业务含义,而非仅作为计算结果的展示层。
第二,QLExpress 更适合"规则型字符串逻辑",而非复杂文本算法 。
它非常擅长表达"条件 + 文本""校验 + 结果说明""循环 + 动态拼接"等规则语义,但并不追求替代模板引擎或文本处理框架。
第三,字符串即规则输出,是规则工程中的重要设计理念 。
无论是校验报告、命中原因,还是策略执行结果,QLExpress 都天然适合直接返回结构化或半结构化的字符串结果,减少规则层与业务层之间的二次转换成本。
第四,良好的边界意识,决定规则系统的长期可维护性 。
将"业务含义明确、逻辑可解释、变更频繁"的字符串逻辑放入 QLExpress;
将"复杂模板渲染、重正则计算、跨语言格式标准"留在应用层处理,是一条被反复验证的工程实践路径。
当你以"规则建模工具"的视角,而非"脚本语言"的视角去使用 QLExpress 时,会发现它在字符串处理上的克制设计,恰恰是其能够长期稳定服务复杂业务系统的重要原因之一。
参考链接
-
QLExpress 官方 GitHub
https://github.com/alibaba/QLExpress -
QLExpress 官方使用文档(语法与执行模型)
-
Java String API 官方文档
https://docs.oracle.com/javase/8/docs/api/java/lang/String.html -
Java 正则表达式(Pattern & Matcher)
https://docs.oracle.com/javase/8/docs/api/java/util/regex/package-summary.html -
规则引擎在企业系统中的典型应用实践(阿里技术博客)
https://developer.aliyun.com/